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, bail};
   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    #[serde(default)]
 1596    pub file_path: Option<PathBuf>,
 1597    #[serde(default)]
 1598    pub line_range: Option<RangeInclusive<u32>>,
 1599}
 1600
 1601impl ClipboardSelection {
 1602    pub fn for_buffer(
 1603        len: usize,
 1604        is_entire_line: bool,
 1605        range: Range<Point>,
 1606        buffer: &MultiBufferSnapshot,
 1607        project: Option<&Entity<Project>>,
 1608        cx: &App,
 1609    ) -> Self {
 1610        let first_line_indent = buffer
 1611            .indent_size_for_line(MultiBufferRow(range.start.row))
 1612            .len;
 1613
 1614        let file_path = util::maybe!({
 1615            let project = project?.read(cx);
 1616            let file = buffer.file_at(range.start)?;
 1617            let project_path = ProjectPath {
 1618                worktree_id: file.worktree_id(cx),
 1619                path: file.path().clone(),
 1620            };
 1621            project.absolute_path(&project_path, cx)
 1622        });
 1623
 1624        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1625
 1626        Self {
 1627            len,
 1628            is_entire_line,
 1629            first_line_indent,
 1630            file_path,
 1631            line_range,
 1632        }
 1633    }
 1634}
 1635
 1636// selections, scroll behavior, was newest selection reversed
 1637type SelectSyntaxNodeHistoryState = (
 1638    Box<[Selection<MultiBufferOffset>]>,
 1639    SelectSyntaxNodeScrollBehavior,
 1640    bool,
 1641);
 1642
 1643#[derive(Default)]
 1644struct SelectSyntaxNodeHistory {
 1645    stack: Vec<SelectSyntaxNodeHistoryState>,
 1646    // disable temporarily to allow changing selections without losing the stack
 1647    pub disable_clearing: bool,
 1648}
 1649
 1650impl SelectSyntaxNodeHistory {
 1651    pub fn try_clear(&mut self) {
 1652        if !self.disable_clearing {
 1653            self.stack.clear();
 1654        }
 1655    }
 1656
 1657    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1658        self.stack.push(selection);
 1659    }
 1660
 1661    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1662        self.stack.pop()
 1663    }
 1664}
 1665
 1666enum SelectSyntaxNodeScrollBehavior {
 1667    CursorTop,
 1668    FitSelection,
 1669    CursorBottom,
 1670}
 1671
 1672#[derive(Debug)]
 1673pub(crate) struct NavigationData {
 1674    cursor_anchor: Anchor,
 1675    cursor_position: Point,
 1676    scroll_anchor: ScrollAnchor,
 1677    scroll_top_row: u32,
 1678}
 1679
 1680#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1681pub enum GotoDefinitionKind {
 1682    Symbol,
 1683    Declaration,
 1684    Type,
 1685    Implementation,
 1686}
 1687
 1688pub enum FormatTarget {
 1689    Buffers(HashSet<Entity<Buffer>>),
 1690    Ranges(Vec<Range<MultiBufferPoint>>),
 1691}
 1692
 1693pub(crate) struct FocusedBlock {
 1694    id: BlockId,
 1695    focus_handle: WeakFocusHandle,
 1696}
 1697
 1698#[derive(Clone, Debug)]
 1699enum JumpData {
 1700    MultiBufferRow {
 1701        row: MultiBufferRow,
 1702        line_offset_from_top: u32,
 1703    },
 1704    MultiBufferPoint {
 1705        excerpt_id: ExcerptId,
 1706        position: Point,
 1707        anchor: text::Anchor,
 1708        line_offset_from_top: u32,
 1709    },
 1710}
 1711
 1712pub enum MultibufferSelectionMode {
 1713    First,
 1714    All,
 1715}
 1716
 1717#[derive(Clone, Copy, Debug, Default)]
 1718pub struct RewrapOptions {
 1719    pub override_language_settings: bool,
 1720    pub preserve_existing_whitespace: bool,
 1721}
 1722
 1723impl Editor {
 1724    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1725        let buffer = cx.new(|cx| Buffer::local("", cx));
 1726        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1727        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1728    }
 1729
 1730    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1731        let buffer = cx.new(|cx| Buffer::local("", cx));
 1732        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1733        Self::new(EditorMode::full(), buffer, None, window, cx)
 1734    }
 1735
 1736    pub fn auto_height(
 1737        min_lines: usize,
 1738        max_lines: usize,
 1739        window: &mut Window,
 1740        cx: &mut Context<Self>,
 1741    ) -> Self {
 1742        let buffer = cx.new(|cx| Buffer::local("", cx));
 1743        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1744        Self::new(
 1745            EditorMode::AutoHeight {
 1746                min_lines,
 1747                max_lines: Some(max_lines),
 1748            },
 1749            buffer,
 1750            None,
 1751            window,
 1752            cx,
 1753        )
 1754    }
 1755
 1756    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1757    /// The editor grows as tall as needed to fit its content.
 1758    pub fn auto_height_unbounded(
 1759        min_lines: usize,
 1760        window: &mut Window,
 1761        cx: &mut Context<Self>,
 1762    ) -> Self {
 1763        let buffer = cx.new(|cx| Buffer::local("", cx));
 1764        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1765        Self::new(
 1766            EditorMode::AutoHeight {
 1767                min_lines,
 1768                max_lines: None,
 1769            },
 1770            buffer,
 1771            None,
 1772            window,
 1773            cx,
 1774        )
 1775    }
 1776
 1777    pub fn for_buffer(
 1778        buffer: Entity<Buffer>,
 1779        project: Option<Entity<Project>>,
 1780        window: &mut Window,
 1781        cx: &mut Context<Self>,
 1782    ) -> Self {
 1783        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1784        Self::new(EditorMode::full(), buffer, project, window, cx)
 1785    }
 1786
 1787    pub fn for_multibuffer(
 1788        buffer: Entity<MultiBuffer>,
 1789        project: Option<Entity<Project>>,
 1790        window: &mut Window,
 1791        cx: &mut Context<Self>,
 1792    ) -> Self {
 1793        Self::new(EditorMode::full(), buffer, project, window, cx)
 1794    }
 1795
 1796    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1797        let mut clone = Self::new(
 1798            self.mode.clone(),
 1799            self.buffer.clone(),
 1800            self.project.clone(),
 1801            window,
 1802            cx,
 1803        );
 1804        self.display_map.update(cx, |display_map, cx| {
 1805            let snapshot = display_map.snapshot(cx);
 1806            clone.display_map.update(cx, |display_map, cx| {
 1807                display_map.set_state(&snapshot, cx);
 1808            });
 1809        });
 1810        clone.folds_did_change(cx);
 1811        clone.selections.clone_state(&self.selections);
 1812        clone.scroll_manager.clone_state(&self.scroll_manager);
 1813        clone.searchable = self.searchable;
 1814        clone.read_only = self.read_only;
 1815        clone
 1816    }
 1817
 1818    pub fn new(
 1819        mode: EditorMode,
 1820        buffer: Entity<MultiBuffer>,
 1821        project: Option<Entity<Project>>,
 1822        window: &mut Window,
 1823        cx: &mut Context<Self>,
 1824    ) -> Self {
 1825        Editor::new_internal(mode, buffer, project, None, window, cx)
 1826    }
 1827
 1828    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1829        let multi_buffer = self.buffer().read(cx);
 1830        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1831        let multi_buffer_visible_start = self
 1832            .scroll_manager
 1833            .anchor()
 1834            .anchor
 1835            .to_point(&multi_buffer_snapshot);
 1836        let max_row = multi_buffer_snapshot.max_point().row;
 1837
 1838        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1839        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1840
 1841        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1842            let outline_items = buffer
 1843                .outline_items_containing(
 1844                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1845                    true,
 1846                    self.style().map(|style| style.syntax.as_ref()),
 1847                )
 1848                .into_iter()
 1849                .map(|outline_item| OutlineItem {
 1850                    depth: outline_item.depth,
 1851                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1852                    source_range_for_text: Anchor::range_in_buffer(
 1853                        *excerpt_id,
 1854                        outline_item.source_range_for_text,
 1855                    ),
 1856                    text: outline_item.text,
 1857                    highlight_ranges: outline_item.highlight_ranges,
 1858                    name_ranges: outline_item.name_ranges,
 1859                    body_range: outline_item
 1860                        .body_range
 1861                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1862                    annotation_range: outline_item
 1863                        .annotation_range
 1864                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1865                });
 1866            return Some(outline_items.collect());
 1867        }
 1868
 1869        None
 1870    }
 1871
 1872    fn new_internal(
 1873        mode: EditorMode,
 1874        multi_buffer: Entity<MultiBuffer>,
 1875        project: Option<Entity<Project>>,
 1876        display_map: Option<Entity<DisplayMap>>,
 1877        window: &mut Window,
 1878        cx: &mut Context<Self>,
 1879    ) -> Self {
 1880        debug_assert!(
 1881            display_map.is_none() || mode.is_minimap(),
 1882            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1883        );
 1884
 1885        let full_mode = mode.is_full();
 1886        let is_minimap = mode.is_minimap();
 1887        let diagnostics_max_severity = if full_mode {
 1888            EditorSettings::get_global(cx)
 1889                .diagnostics_max_severity
 1890                .unwrap_or(DiagnosticSeverity::Hint)
 1891        } else {
 1892            DiagnosticSeverity::Off
 1893        };
 1894        let style = window.text_style();
 1895        let font_size = style.font_size.to_pixels(window.rem_size());
 1896        let editor = cx.entity().downgrade();
 1897        let fold_placeholder = FoldPlaceholder {
 1898            constrain_width: false,
 1899            render: Arc::new(move |fold_id, fold_range, cx| {
 1900                let editor = editor.clone();
 1901                div()
 1902                    .id(fold_id)
 1903                    .bg(cx.theme().colors().ghost_element_background)
 1904                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1905                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1906                    .rounded_xs()
 1907                    .size_full()
 1908                    .cursor_pointer()
 1909                    .child("")
 1910                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1911                    .on_click(move |_, _window, cx| {
 1912                        editor
 1913                            .update(cx, |editor, cx| {
 1914                                editor.unfold_ranges(
 1915                                    &[fold_range.start..fold_range.end],
 1916                                    true,
 1917                                    false,
 1918                                    cx,
 1919                                );
 1920                                cx.stop_propagation();
 1921                            })
 1922                            .ok();
 1923                    })
 1924                    .into_any()
 1925            }),
 1926            merge_adjacent: true,
 1927            ..FoldPlaceholder::default()
 1928        };
 1929        let display_map = display_map.unwrap_or_else(|| {
 1930            cx.new(|cx| {
 1931                DisplayMap::new(
 1932                    multi_buffer.clone(),
 1933                    style.font(),
 1934                    font_size,
 1935                    None,
 1936                    FILE_HEADER_HEIGHT,
 1937                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1938                    fold_placeholder,
 1939                    diagnostics_max_severity,
 1940                    cx,
 1941                )
 1942            })
 1943        });
 1944
 1945        let selections = SelectionsCollection::new();
 1946
 1947        let blink_manager = cx.new(|cx| {
 1948            let mut blink_manager = BlinkManager::new(
 1949                CURSOR_BLINK_INTERVAL,
 1950                |cx| EditorSettings::get_global(cx).cursor_blink,
 1951                cx,
 1952            );
 1953            if is_minimap {
 1954                blink_manager.disable(cx);
 1955            }
 1956            blink_manager
 1957        });
 1958
 1959        let soft_wrap_mode_override =
 1960            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1961
 1962        let mut project_subscriptions = Vec::new();
 1963        if full_mode && let Some(project) = project.as_ref() {
 1964            project_subscriptions.push(cx.subscribe_in(
 1965                project,
 1966                window,
 1967                |editor, _, event, window, cx| match event {
 1968                    project::Event::RefreshCodeLens => {
 1969                        // we always query lens with actions, without storing them, always refreshing them
 1970                    }
 1971                    project::Event::RefreshInlayHints {
 1972                        server_id,
 1973                        request_id,
 1974                    } => {
 1975                        editor.refresh_inlay_hints(
 1976                            InlayHintRefreshReason::RefreshRequested {
 1977                                server_id: *server_id,
 1978                                request_id: *request_id,
 1979                            },
 1980                            cx,
 1981                        );
 1982                    }
 1983                    project::Event::LanguageServerRemoved(..) => {
 1984                        if editor.tasks_update_task.is_none() {
 1985                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1986                        }
 1987                        editor.registered_buffers.clear();
 1988                        editor.register_visible_buffers(cx);
 1989                    }
 1990                    project::Event::LanguageServerAdded(..) => {
 1991                        if editor.tasks_update_task.is_none() {
 1992                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1993                        }
 1994                    }
 1995                    project::Event::SnippetEdit(id, snippet_edits) => {
 1996                        // todo(lw): Non singletons
 1997                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 1998                            let snapshot = buffer.read(cx).snapshot();
 1999                            let focus_handle = editor.focus_handle(cx);
 2000                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2001                                for (range, snippet) in snippet_edits {
 2002                                    let buffer_range =
 2003                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2004                                    editor
 2005                                        .insert_snippet(
 2006                                            &[MultiBufferOffset(buffer_range.start)
 2007                                                ..MultiBufferOffset(buffer_range.end)],
 2008                                            snippet.clone(),
 2009                                            window,
 2010                                            cx,
 2011                                        )
 2012                                        .ok();
 2013                                }
 2014                            }
 2015                        }
 2016                    }
 2017                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2018                        let buffer_id = *buffer_id;
 2019                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2020                            editor.register_buffer(buffer_id, cx);
 2021                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2022                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2023                            refresh_linked_ranges(editor, window, cx);
 2024                            editor.refresh_code_actions(window, cx);
 2025                            editor.refresh_document_highlights(cx);
 2026                        }
 2027                    }
 2028
 2029                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2030                        let Some(workspace) = editor.workspace() else {
 2031                            return;
 2032                        };
 2033                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2034                        else {
 2035                            return;
 2036                        };
 2037
 2038                        if active_editor.entity_id() == cx.entity_id() {
 2039                            let entity_id = cx.entity_id();
 2040                            workspace.update(cx, |this, cx| {
 2041                                this.panes_mut()
 2042                                    .iter_mut()
 2043                                    .filter(|pane| pane.entity_id() != entity_id)
 2044                                    .for_each(|p| {
 2045                                        p.update(cx, |pane, _| {
 2046                                            pane.nav_history_mut().rename_item(
 2047                                                entity_id,
 2048                                                project_path.clone(),
 2049                                                abs_path.clone().into(),
 2050                                            );
 2051                                        })
 2052                                    });
 2053                            });
 2054                            let edited_buffers_already_open = {
 2055                                let other_editors: Vec<Entity<Editor>> = workspace
 2056                                    .read(cx)
 2057                                    .panes()
 2058                                    .iter()
 2059                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 2060                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2061                                    .collect();
 2062
 2063                                transaction.0.keys().all(|buffer| {
 2064                                    other_editors.iter().any(|editor| {
 2065                                        let multi_buffer = editor.read(cx).buffer();
 2066                                        multi_buffer.read(cx).is_singleton()
 2067                                            && multi_buffer.read(cx).as_singleton().map_or(
 2068                                                false,
 2069                                                |singleton| {
 2070                                                    singleton.entity_id() == buffer.entity_id()
 2071                                                },
 2072                                            )
 2073                                    })
 2074                                })
 2075                            };
 2076                            if !edited_buffers_already_open {
 2077                                let workspace = workspace.downgrade();
 2078                                let transaction = transaction.clone();
 2079                                cx.defer_in(window, move |_, window, cx| {
 2080                                    cx.spawn_in(window, async move |editor, cx| {
 2081                                        Self::open_project_transaction(
 2082                                            &editor,
 2083                                            workspace,
 2084                                            transaction,
 2085                                            "Rename".to_string(),
 2086                                            cx,
 2087                                        )
 2088                                        .await
 2089                                        .ok()
 2090                                    })
 2091                                    .detach();
 2092                                });
 2093                            }
 2094                        }
 2095                    }
 2096
 2097                    _ => {}
 2098                },
 2099            ));
 2100            if let Some(task_inventory) = project
 2101                .read(cx)
 2102                .task_store()
 2103                .read(cx)
 2104                .task_inventory()
 2105                .cloned()
 2106            {
 2107                project_subscriptions.push(cx.observe_in(
 2108                    &task_inventory,
 2109                    window,
 2110                    |editor, _, window, cx| {
 2111                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2112                    },
 2113                ));
 2114            };
 2115
 2116            project_subscriptions.push(cx.subscribe_in(
 2117                &project.read(cx).breakpoint_store(),
 2118                window,
 2119                |editor, _, event, window, cx| match event {
 2120                    BreakpointStoreEvent::ClearDebugLines => {
 2121                        editor.clear_row_highlights::<ActiveDebugLine>();
 2122                        editor.refresh_inline_values(cx);
 2123                    }
 2124                    BreakpointStoreEvent::SetDebugLine => {
 2125                        if editor.go_to_active_debug_line(window, cx) {
 2126                            cx.stop_propagation();
 2127                        }
 2128
 2129                        editor.refresh_inline_values(cx);
 2130                    }
 2131                    _ => {}
 2132                },
 2133            ));
 2134            let git_store = project.read(cx).git_store().clone();
 2135            let project = project.clone();
 2136            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2137                if let GitStoreEvent::RepositoryAdded = event {
 2138                    this.load_diff_task = Some(
 2139                        update_uncommitted_diff_for_buffer(
 2140                            cx.entity(),
 2141                            &project,
 2142                            this.buffer.read(cx).all_buffers(),
 2143                            this.buffer.clone(),
 2144                            cx,
 2145                        )
 2146                        .shared(),
 2147                    );
 2148                }
 2149            }));
 2150        }
 2151
 2152        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2153
 2154        let inlay_hint_settings =
 2155            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2156        let focus_handle = cx.focus_handle();
 2157        if !is_minimap {
 2158            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2159                .detach();
 2160            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2161                .detach();
 2162            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2163                .detach();
 2164            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2165                .detach();
 2166            cx.observe_pending_input(window, Self::observe_pending_input)
 2167                .detach();
 2168        }
 2169
 2170        let show_indent_guides =
 2171            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2172                Some(false)
 2173            } else {
 2174                None
 2175            };
 2176
 2177        let breakpoint_store = match (&mode, project.as_ref()) {
 2178            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2179            _ => None,
 2180        };
 2181
 2182        let mut code_action_providers = Vec::new();
 2183        let mut load_uncommitted_diff = None;
 2184        if let Some(project) = project.clone() {
 2185            load_uncommitted_diff = Some(
 2186                update_uncommitted_diff_for_buffer(
 2187                    cx.entity(),
 2188                    &project,
 2189                    multi_buffer.read(cx).all_buffers(),
 2190                    multi_buffer.clone(),
 2191                    cx,
 2192                )
 2193                .shared(),
 2194            );
 2195            code_action_providers.push(Rc::new(project) as Rc<_>);
 2196        }
 2197
 2198        let mut editor = Self {
 2199            focus_handle,
 2200            show_cursor_when_unfocused: false,
 2201            last_focused_descendant: None,
 2202            buffer: multi_buffer.clone(),
 2203            display_map: display_map.clone(),
 2204            placeholder_display_map: None,
 2205            selections,
 2206            scroll_manager: ScrollManager::new(cx),
 2207            columnar_selection_state: None,
 2208            add_selections_state: None,
 2209            select_next_state: None,
 2210            select_prev_state: None,
 2211            selection_history: SelectionHistory::default(),
 2212            defer_selection_effects: false,
 2213            deferred_selection_effects_state: None,
 2214            autoclose_regions: Vec::new(),
 2215            snippet_stack: InvalidationStack::default(),
 2216            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2217            ime_transaction: None,
 2218            active_diagnostics: ActiveDiagnostic::None,
 2219            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2220            inline_diagnostics_update: Task::ready(()),
 2221            inline_diagnostics: Vec::new(),
 2222            soft_wrap_mode_override,
 2223            diagnostics_max_severity,
 2224            hard_wrap: None,
 2225            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2226            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2227            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2228            project,
 2229            blink_manager: blink_manager.clone(),
 2230            show_local_selections: true,
 2231            show_scrollbars: ScrollbarAxes {
 2232                horizontal: full_mode,
 2233                vertical: full_mode,
 2234            },
 2235            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2236            offset_content: !matches!(mode, EditorMode::SingleLine),
 2237            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2238            show_gutter: full_mode,
 2239            show_line_numbers: (!full_mode).then_some(false),
 2240            use_relative_line_numbers: None,
 2241            disable_expand_excerpt_buttons: !full_mode,
 2242            show_git_diff_gutter: None,
 2243            show_code_actions: None,
 2244            show_runnables: None,
 2245            show_breakpoints: None,
 2246            show_wrap_guides: None,
 2247            show_indent_guides,
 2248            buffers_with_disabled_indent_guides: HashSet::default(),
 2249            highlight_order: 0,
 2250            highlighted_rows: HashMap::default(),
 2251            background_highlights: HashMap::default(),
 2252            gutter_highlights: HashMap::default(),
 2253            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2254            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2255            nav_history: None,
 2256            context_menu: RefCell::new(None),
 2257            context_menu_options: None,
 2258            mouse_context_menu: None,
 2259            completion_tasks: Vec::new(),
 2260            inline_blame_popover: None,
 2261            inline_blame_popover_show_task: None,
 2262            signature_help_state: SignatureHelpState::default(),
 2263            auto_signature_help: None,
 2264            find_all_references_task_sources: Vec::new(),
 2265            next_completion_id: 0,
 2266            next_inlay_id: 0,
 2267            code_action_providers,
 2268            available_code_actions: None,
 2269            code_actions_task: None,
 2270            quick_selection_highlight_task: None,
 2271            debounced_selection_highlight_task: None,
 2272            document_highlights_task: None,
 2273            linked_editing_range_task: None,
 2274            pending_rename: None,
 2275            searchable: !is_minimap,
 2276            cursor_shape: EditorSettings::get_global(cx)
 2277                .cursor_shape
 2278                .unwrap_or_default(),
 2279            current_line_highlight: None,
 2280            autoindent_mode: Some(AutoindentMode::EachLine),
 2281            collapse_matches: false,
 2282            workspace: None,
 2283            input_enabled: !is_minimap,
 2284            use_modal_editing: full_mode,
 2285            read_only: is_minimap,
 2286            use_autoclose: true,
 2287            use_auto_surround: true,
 2288            auto_replace_emoji_shortcode: false,
 2289            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2290            leader_id: None,
 2291            remote_id: None,
 2292            hover_state: HoverState::default(),
 2293            pending_mouse_down: None,
 2294            hovered_link_state: None,
 2295            edit_prediction_provider: None,
 2296            active_edit_prediction: None,
 2297            stale_edit_prediction_in_menu: None,
 2298            edit_prediction_preview: EditPredictionPreview::Inactive {
 2299                released_too_fast: false,
 2300            },
 2301            inline_diagnostics_enabled: full_mode,
 2302            diagnostics_enabled: full_mode,
 2303            word_completions_enabled: full_mode,
 2304            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2305            gutter_hovered: false,
 2306            pixel_position_of_newest_cursor: None,
 2307            last_bounds: None,
 2308            last_position_map: None,
 2309            expect_bounds_change: None,
 2310            gutter_dimensions: GutterDimensions::default(),
 2311            style: None,
 2312            show_cursor_names: false,
 2313            hovered_cursors: HashMap::default(),
 2314            next_editor_action_id: EditorActionId::default(),
 2315            editor_actions: Rc::default(),
 2316            edit_predictions_hidden_for_vim_mode: false,
 2317            show_edit_predictions_override: None,
 2318            show_completions_on_input_override: None,
 2319            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2320            edit_prediction_settings: EditPredictionSettings::Disabled,
 2321            edit_prediction_indent_conflict: false,
 2322            edit_prediction_requires_modifier_in_indent_conflict: true,
 2323            custom_context_menu: None,
 2324            show_git_blame_gutter: false,
 2325            show_git_blame_inline: false,
 2326            show_selection_menu: None,
 2327            show_git_blame_inline_delay_task: None,
 2328            git_blame_inline_enabled: full_mode
 2329                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2330            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2331            buffer_serialization: is_minimap.not().then(|| {
 2332                BufferSerialization::new(
 2333                    ProjectSettings::get_global(cx)
 2334                        .session
 2335                        .restore_unsaved_buffers,
 2336                )
 2337            }),
 2338            blame: None,
 2339            blame_subscription: None,
 2340            tasks: BTreeMap::default(),
 2341
 2342            breakpoint_store,
 2343            gutter_breakpoint_indicator: (None, None),
 2344            hovered_diff_hunk_row: None,
 2345            _subscriptions: (!is_minimap)
 2346                .then(|| {
 2347                    vec![
 2348                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2349                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2350                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2351                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2352                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2353                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2354                        cx.observe_window_activation(window, |editor, window, cx| {
 2355                            let active = window.is_window_active();
 2356                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2357                                if active {
 2358                                    blink_manager.enable(cx);
 2359                                } else {
 2360                                    blink_manager.disable(cx);
 2361                                }
 2362                            });
 2363                            if active {
 2364                                editor.show_mouse_cursor(cx);
 2365                            }
 2366                        }),
 2367                    ]
 2368                })
 2369                .unwrap_or_default(),
 2370            tasks_update_task: None,
 2371            pull_diagnostics_task: Task::ready(()),
 2372            pull_diagnostics_background_task: Task::ready(()),
 2373            colors: None,
 2374            refresh_colors_task: Task::ready(()),
 2375            inlay_hints: None,
 2376            next_color_inlay_id: 0,
 2377            post_scroll_update: Task::ready(()),
 2378            linked_edit_ranges: Default::default(),
 2379            in_project_search: false,
 2380            previous_search_ranges: None,
 2381            breadcrumb_header: None,
 2382            focused_block: None,
 2383            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2384            addons: HashMap::default(),
 2385            registered_buffers: HashMap::default(),
 2386            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2387            selection_mark_mode: false,
 2388            toggle_fold_multiple_buffers: Task::ready(()),
 2389            serialize_selections: Task::ready(()),
 2390            serialize_folds: Task::ready(()),
 2391            text_style_refinement: None,
 2392            load_diff_task: load_uncommitted_diff,
 2393            temporary_diff_override: false,
 2394            mouse_cursor_hidden: false,
 2395            minimap: None,
 2396            hide_mouse_mode: EditorSettings::get_global(cx)
 2397                .hide_mouse
 2398                .unwrap_or_default(),
 2399            change_list: ChangeList::new(),
 2400            mode,
 2401            selection_drag_state: SelectionDragState::None,
 2402            folding_newlines: Task::ready(()),
 2403            lookup_key: None,
 2404            select_next_is_case_sensitive: None,
 2405            applicable_language_settings: HashMap::default(),
 2406            accent_data: None,
 2407            fetched_tree_sitter_chunks: HashMap::default(),
 2408            use_base_text_line_numbers: false,
 2409        };
 2410
 2411        if is_minimap {
 2412            return editor;
 2413        }
 2414
 2415        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2416        editor.accent_data = editor.fetch_accent_data(cx);
 2417
 2418        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2419            editor
 2420                ._subscriptions
 2421                .push(cx.observe(breakpoints, |_, _, cx| {
 2422                    cx.notify();
 2423                }));
 2424        }
 2425        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2426        editor._subscriptions.extend(project_subscriptions);
 2427
 2428        editor._subscriptions.push(cx.subscribe_in(
 2429            &cx.entity(),
 2430            window,
 2431            |editor, _, e: &EditorEvent, window, cx| match e {
 2432                EditorEvent::ScrollPositionChanged { local, .. } => {
 2433                    if *local {
 2434                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2435                        editor.inline_blame_popover.take();
 2436                        let new_anchor = editor.scroll_manager.anchor();
 2437                        let snapshot = editor.snapshot(window, cx);
 2438                        editor.update_restoration_data(cx, move |data| {
 2439                            data.scroll_position = (
 2440                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2441                                new_anchor.offset,
 2442                            );
 2443                        });
 2444
 2445                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2446                            cx.background_executor()
 2447                                .timer(Duration::from_millis(50))
 2448                                .await;
 2449                            editor
 2450                                .update_in(cx, |editor, window, cx| {
 2451                                    editor.register_visible_buffers(cx);
 2452                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2453                                    editor.refresh_inlay_hints(
 2454                                        InlayHintRefreshReason::NewLinesShown,
 2455                                        cx,
 2456                                    );
 2457                                    editor.colorize_brackets(false, cx);
 2458                                })
 2459                                .ok();
 2460                        });
 2461                    }
 2462                }
 2463                EditorEvent::Edited { .. } => {
 2464                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2465                        .map(|vim_mode| vim_mode.0)
 2466                        .unwrap_or(false);
 2467                    if !vim_mode {
 2468                        let display_map = editor.display_snapshot(cx);
 2469                        let selections = editor.selections.all_adjusted_display(&display_map);
 2470                        let pop_state = editor
 2471                            .change_list
 2472                            .last()
 2473                            .map(|previous| {
 2474                                previous.len() == selections.len()
 2475                                    && previous.iter().enumerate().all(|(ix, p)| {
 2476                                        p.to_display_point(&display_map).row()
 2477                                            == selections[ix].head().row()
 2478                                    })
 2479                            })
 2480                            .unwrap_or(false);
 2481                        let new_positions = selections
 2482                            .into_iter()
 2483                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2484                            .collect();
 2485                        editor
 2486                            .change_list
 2487                            .push_to_change_list(pop_state, new_positions);
 2488                    }
 2489                }
 2490                _ => (),
 2491            },
 2492        ));
 2493
 2494        if let Some(dap_store) = editor
 2495            .project
 2496            .as_ref()
 2497            .map(|project| project.read(cx).dap_store())
 2498        {
 2499            let weak_editor = cx.weak_entity();
 2500
 2501            editor
 2502                ._subscriptions
 2503                .push(
 2504                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2505                        let session_entity = cx.entity();
 2506                        weak_editor
 2507                            .update(cx, |editor, cx| {
 2508                                editor._subscriptions.push(
 2509                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2510                                );
 2511                            })
 2512                            .ok();
 2513                    }),
 2514                );
 2515
 2516            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2517                editor
 2518                    ._subscriptions
 2519                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2520            }
 2521        }
 2522
 2523        // skip adding the initial selection to selection history
 2524        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2525        editor.end_selection(window, cx);
 2526        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2527
 2528        editor.scroll_manager.show_scrollbars(window, cx);
 2529        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2530
 2531        if full_mode {
 2532            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2533            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2534
 2535            if editor.git_blame_inline_enabled {
 2536                editor.start_git_blame_inline(false, window, cx);
 2537            }
 2538
 2539            editor.go_to_active_debug_line(window, cx);
 2540
 2541            editor.minimap =
 2542                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2543            editor.colors = Some(LspColorData::new(cx));
 2544            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2545
 2546            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2547                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2548            }
 2549            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2550        }
 2551
 2552        editor
 2553    }
 2554
 2555    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2556        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2557    }
 2558
 2559    pub fn deploy_mouse_context_menu(
 2560        &mut self,
 2561        position: gpui::Point<Pixels>,
 2562        context_menu: Entity<ContextMenu>,
 2563        window: &mut Window,
 2564        cx: &mut Context<Self>,
 2565    ) {
 2566        self.mouse_context_menu = Some(MouseContextMenu::new(
 2567            self,
 2568            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2569            context_menu,
 2570            window,
 2571            cx,
 2572        ));
 2573    }
 2574
 2575    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2576        self.mouse_context_menu
 2577            .as_ref()
 2578            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2579    }
 2580
 2581    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2582        if self
 2583            .selections
 2584            .pending_anchor()
 2585            .is_some_and(|pending_selection| {
 2586                let snapshot = self.buffer().read(cx).snapshot(cx);
 2587                pending_selection.range().includes(range, &snapshot)
 2588            })
 2589        {
 2590            return true;
 2591        }
 2592
 2593        self.selections
 2594            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2595            .into_iter()
 2596            .any(|selection| {
 2597                // This is needed to cover a corner case, if we just check for an existing
 2598                // selection in the fold range, having a cursor at the start of the fold
 2599                // marks it as selected. Non-empty selections don't cause this.
 2600                let length = selection.end - selection.start;
 2601                length > 0
 2602            })
 2603    }
 2604
 2605    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2606        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2607    }
 2608
 2609    fn key_context_internal(
 2610        &self,
 2611        has_active_edit_prediction: bool,
 2612        window: &mut Window,
 2613        cx: &mut App,
 2614    ) -> KeyContext {
 2615        let mut key_context = KeyContext::new_with_defaults();
 2616        key_context.add("Editor");
 2617        let mode = match self.mode {
 2618            EditorMode::SingleLine => "single_line",
 2619            EditorMode::AutoHeight { .. } => "auto_height",
 2620            EditorMode::Minimap { .. } => "minimap",
 2621            EditorMode::Full { .. } => "full",
 2622        };
 2623
 2624        if EditorSettings::jupyter_enabled(cx) {
 2625            key_context.add("jupyter");
 2626        }
 2627
 2628        key_context.set("mode", mode);
 2629        if self.pending_rename.is_some() {
 2630            key_context.add("renaming");
 2631        }
 2632
 2633        if let Some(snippet_stack) = self.snippet_stack.last() {
 2634            key_context.add("in_snippet");
 2635
 2636            if snippet_stack.active_index > 0 {
 2637                key_context.add("has_previous_tabstop");
 2638            }
 2639
 2640            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2641                key_context.add("has_next_tabstop");
 2642            }
 2643        }
 2644
 2645        match self.context_menu.borrow().as_ref() {
 2646            Some(CodeContextMenu::Completions(menu)) => {
 2647                if menu.visible() {
 2648                    key_context.add("menu");
 2649                    key_context.add("showing_completions");
 2650                }
 2651            }
 2652            Some(CodeContextMenu::CodeActions(menu)) => {
 2653                if menu.visible() {
 2654                    key_context.add("menu");
 2655                    key_context.add("showing_code_actions")
 2656                }
 2657            }
 2658            None => {}
 2659        }
 2660
 2661        if self.signature_help_state.has_multiple_signatures() {
 2662            key_context.add("showing_signature_help");
 2663        }
 2664
 2665        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2666        if !self.focus_handle(cx).contains_focused(window, cx)
 2667            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2668        {
 2669            for addon in self.addons.values() {
 2670                addon.extend_key_context(&mut key_context, cx)
 2671            }
 2672        }
 2673
 2674        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2675            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2676                Some(
 2677                    file.full_path(cx)
 2678                        .extension()?
 2679                        .to_string_lossy()
 2680                        .into_owned(),
 2681                )
 2682            }) {
 2683                key_context.set("extension", extension);
 2684            }
 2685        } else {
 2686            key_context.add("multibuffer");
 2687        }
 2688
 2689        if has_active_edit_prediction {
 2690            if self.edit_prediction_in_conflict() {
 2691                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2692            } else {
 2693                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2694                key_context.add("copilot_suggestion");
 2695            }
 2696        }
 2697
 2698        if self.selection_mark_mode {
 2699            key_context.add("selection_mode");
 2700        }
 2701
 2702        let disjoint = self.selections.disjoint_anchors();
 2703        let snapshot = self.snapshot(window, cx);
 2704        let snapshot = snapshot.buffer_snapshot();
 2705        if self.mode == EditorMode::SingleLine
 2706            && let [selection] = disjoint
 2707            && selection.start == selection.end
 2708            && selection.end.to_offset(snapshot) == snapshot.len()
 2709        {
 2710            key_context.add("end_of_input");
 2711        }
 2712
 2713        if self.has_any_expanded_diff_hunks(cx) {
 2714            key_context.add("diffs_expanded");
 2715        }
 2716
 2717        key_context
 2718    }
 2719
 2720    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2721        self.last_bounds.as_ref()
 2722    }
 2723
 2724    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2725        if self.mouse_cursor_hidden {
 2726            self.mouse_cursor_hidden = false;
 2727            cx.notify();
 2728        }
 2729    }
 2730
 2731    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2732        let hide_mouse_cursor = match origin {
 2733            HideMouseCursorOrigin::TypingAction => {
 2734                matches!(
 2735                    self.hide_mouse_mode,
 2736                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2737                )
 2738            }
 2739            HideMouseCursorOrigin::MovementAction => {
 2740                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2741            }
 2742        };
 2743        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2744            self.mouse_cursor_hidden = hide_mouse_cursor;
 2745            cx.notify();
 2746        }
 2747    }
 2748
 2749    pub fn edit_prediction_in_conflict(&self) -> bool {
 2750        if !self.show_edit_predictions_in_menu() {
 2751            return false;
 2752        }
 2753
 2754        let showing_completions = self
 2755            .context_menu
 2756            .borrow()
 2757            .as_ref()
 2758            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2759
 2760        showing_completions
 2761            || self.edit_prediction_requires_modifier()
 2762            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2763            // bindings to insert tab characters.
 2764            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2765    }
 2766
 2767    pub fn accept_edit_prediction_keybind(
 2768        &self,
 2769        accept_partial: bool,
 2770        window: &mut Window,
 2771        cx: &mut App,
 2772    ) -> AcceptEditPredictionBinding {
 2773        let key_context = self.key_context_internal(true, window, cx);
 2774        let in_conflict = self.edit_prediction_in_conflict();
 2775
 2776        let bindings = if accept_partial {
 2777            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2778        } else {
 2779            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2780        };
 2781
 2782        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2783        // just the first one.
 2784        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2785            !in_conflict
 2786                || binding
 2787                    .keystrokes()
 2788                    .first()
 2789                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2790        }))
 2791    }
 2792
 2793    pub fn new_file(
 2794        workspace: &mut Workspace,
 2795        _: &workspace::NewFile,
 2796        window: &mut Window,
 2797        cx: &mut Context<Workspace>,
 2798    ) {
 2799        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2800            "Failed to create buffer",
 2801            window,
 2802            cx,
 2803            |e, _, _| match e.error_code() {
 2804                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2805                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2806                e.error_tag("required").unwrap_or("the latest version")
 2807            )),
 2808                _ => None,
 2809            },
 2810        );
 2811    }
 2812
 2813    pub fn new_in_workspace(
 2814        workspace: &mut Workspace,
 2815        window: &mut Window,
 2816        cx: &mut Context<Workspace>,
 2817    ) -> Task<Result<Entity<Editor>>> {
 2818        let project = workspace.project().clone();
 2819        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2820
 2821        cx.spawn_in(window, async move |workspace, cx| {
 2822            let buffer = create.await?;
 2823            workspace.update_in(cx, |workspace, window, cx| {
 2824                let editor =
 2825                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2826                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2827                editor
 2828            })
 2829        })
 2830    }
 2831
 2832    fn new_file_vertical(
 2833        workspace: &mut Workspace,
 2834        _: &workspace::NewFileSplitVertical,
 2835        window: &mut Window,
 2836        cx: &mut Context<Workspace>,
 2837    ) {
 2838        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2839    }
 2840
 2841    fn new_file_horizontal(
 2842        workspace: &mut Workspace,
 2843        _: &workspace::NewFileSplitHorizontal,
 2844        window: &mut Window,
 2845        cx: &mut Context<Workspace>,
 2846    ) {
 2847        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2848    }
 2849
 2850    fn new_file_split(
 2851        workspace: &mut Workspace,
 2852        action: &workspace::NewFileSplit,
 2853        window: &mut Window,
 2854        cx: &mut Context<Workspace>,
 2855    ) {
 2856        Self::new_file_in_direction(workspace, action.0, window, cx)
 2857    }
 2858
 2859    fn new_file_in_direction(
 2860        workspace: &mut Workspace,
 2861        direction: SplitDirection,
 2862        window: &mut Window,
 2863        cx: &mut Context<Workspace>,
 2864    ) {
 2865        let project = workspace.project().clone();
 2866        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2867
 2868        cx.spawn_in(window, async move |workspace, cx| {
 2869            let buffer = create.await?;
 2870            workspace.update_in(cx, move |workspace, window, cx| {
 2871                workspace.split_item(
 2872                    direction,
 2873                    Box::new(
 2874                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2875                    ),
 2876                    window,
 2877                    cx,
 2878                )
 2879            })?;
 2880            anyhow::Ok(())
 2881        })
 2882        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2883            match e.error_code() {
 2884                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2885                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2886                e.error_tag("required").unwrap_or("the latest version")
 2887            )),
 2888                _ => None,
 2889            }
 2890        });
 2891    }
 2892
 2893    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2894        self.leader_id
 2895    }
 2896
 2897    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2898        &self.buffer
 2899    }
 2900
 2901    pub fn project(&self) -> Option<&Entity<Project>> {
 2902        self.project.as_ref()
 2903    }
 2904
 2905    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2906        self.workspace.as_ref()?.0.upgrade()
 2907    }
 2908
 2909    /// Returns the workspace serialization ID if this editor should be serialized.
 2910    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2911        self.workspace
 2912            .as_ref()
 2913            .filter(|_| self.should_serialize_buffer())
 2914            .and_then(|workspace| workspace.1)
 2915    }
 2916
 2917    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2918        self.buffer().read(cx).title(cx)
 2919    }
 2920
 2921    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2922        let git_blame_gutter_max_author_length = self
 2923            .render_git_blame_gutter(cx)
 2924            .then(|| {
 2925                if let Some(blame) = self.blame.as_ref() {
 2926                    let max_author_length =
 2927                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2928                    Some(max_author_length)
 2929                } else {
 2930                    None
 2931                }
 2932            })
 2933            .flatten();
 2934
 2935        EditorSnapshot {
 2936            mode: self.mode.clone(),
 2937            show_gutter: self.show_gutter,
 2938            show_line_numbers: self.show_line_numbers,
 2939            show_git_diff_gutter: self.show_git_diff_gutter,
 2940            show_code_actions: self.show_code_actions,
 2941            show_runnables: self.show_runnables,
 2942            show_breakpoints: self.show_breakpoints,
 2943            git_blame_gutter_max_author_length,
 2944            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2945            placeholder_display_snapshot: self
 2946                .placeholder_display_map
 2947                .as_ref()
 2948                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2949            scroll_anchor: self.scroll_manager.anchor(),
 2950            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2951            is_focused: self.focus_handle.is_focused(window),
 2952            current_line_highlight: self
 2953                .current_line_highlight
 2954                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2955            gutter_hovered: self.gutter_hovered,
 2956        }
 2957    }
 2958
 2959    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2960        self.buffer.read(cx).language_at(point, cx)
 2961    }
 2962
 2963    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2964        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2965    }
 2966
 2967    pub fn active_excerpt(
 2968        &self,
 2969        cx: &App,
 2970    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2971        self.buffer
 2972            .read(cx)
 2973            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2974    }
 2975
 2976    pub fn mode(&self) -> &EditorMode {
 2977        &self.mode
 2978    }
 2979
 2980    pub fn set_mode(&mut self, mode: EditorMode) {
 2981        self.mode = mode;
 2982    }
 2983
 2984    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2985        self.collaboration_hub.as_deref()
 2986    }
 2987
 2988    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2989        self.collaboration_hub = Some(hub);
 2990    }
 2991
 2992    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2993        self.in_project_search = in_project_search;
 2994    }
 2995
 2996    pub fn set_custom_context_menu(
 2997        &mut self,
 2998        f: impl 'static
 2999        + Fn(
 3000            &mut Self,
 3001            DisplayPoint,
 3002            &mut Window,
 3003            &mut Context<Self>,
 3004        ) -> Option<Entity<ui::ContextMenu>>,
 3005    ) {
 3006        self.custom_context_menu = Some(Box::new(f))
 3007    }
 3008
 3009    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3010        self.completion_provider = provider;
 3011    }
 3012
 3013    #[cfg(any(test, feature = "test-support"))]
 3014    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3015        self.completion_provider.clone()
 3016    }
 3017
 3018    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3019        self.semantics_provider.clone()
 3020    }
 3021
 3022    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3023        self.semantics_provider = provider;
 3024    }
 3025
 3026    pub fn set_edit_prediction_provider<T>(
 3027        &mut self,
 3028        provider: Option<Entity<T>>,
 3029        window: &mut Window,
 3030        cx: &mut Context<Self>,
 3031    ) where
 3032        T: EditPredictionDelegate,
 3033    {
 3034        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3035            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3036                if this.focus_handle.is_focused(window) {
 3037                    this.update_visible_edit_prediction(window, cx);
 3038                }
 3039            }),
 3040            provider: Arc::new(provider),
 3041        });
 3042        self.update_edit_prediction_settings(cx);
 3043        self.refresh_edit_prediction(false, false, window, cx);
 3044    }
 3045
 3046    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3047        self.placeholder_display_map
 3048            .as_ref()
 3049            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3050    }
 3051
 3052    pub fn set_placeholder_text(
 3053        &mut self,
 3054        placeholder_text: &str,
 3055        window: &mut Window,
 3056        cx: &mut Context<Self>,
 3057    ) {
 3058        let multibuffer = cx
 3059            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3060
 3061        let style = window.text_style();
 3062
 3063        self.placeholder_display_map = Some(cx.new(|cx| {
 3064            DisplayMap::new(
 3065                multibuffer,
 3066                style.font(),
 3067                style.font_size.to_pixels(window.rem_size()),
 3068                None,
 3069                FILE_HEADER_HEIGHT,
 3070                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3071                Default::default(),
 3072                DiagnosticSeverity::Off,
 3073                cx,
 3074            )
 3075        }));
 3076        cx.notify();
 3077    }
 3078
 3079    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3080        self.cursor_shape = cursor_shape;
 3081
 3082        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3083        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3084
 3085        cx.notify();
 3086    }
 3087
 3088    pub fn cursor_shape(&self) -> CursorShape {
 3089        self.cursor_shape
 3090    }
 3091
 3092    pub fn set_current_line_highlight(
 3093        &mut self,
 3094        current_line_highlight: Option<CurrentLineHighlight>,
 3095    ) {
 3096        self.current_line_highlight = current_line_highlight;
 3097    }
 3098
 3099    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3100        self.collapse_matches = collapse_matches;
 3101    }
 3102
 3103    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3104        if self.collapse_matches {
 3105            return range.start..range.start;
 3106        }
 3107        range.clone()
 3108    }
 3109
 3110    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3111        self.display_map.read(cx).clip_at_line_ends
 3112    }
 3113
 3114    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3115        if self.display_map.read(cx).clip_at_line_ends != clip {
 3116            self.display_map
 3117                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3118        }
 3119    }
 3120
 3121    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3122        self.input_enabled = input_enabled;
 3123    }
 3124
 3125    pub fn set_edit_predictions_hidden_for_vim_mode(
 3126        &mut self,
 3127        hidden: bool,
 3128        window: &mut Window,
 3129        cx: &mut Context<Self>,
 3130    ) {
 3131        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3132            self.edit_predictions_hidden_for_vim_mode = hidden;
 3133            if hidden {
 3134                self.update_visible_edit_prediction(window, cx);
 3135            } else {
 3136                self.refresh_edit_prediction(true, false, window, cx);
 3137            }
 3138        }
 3139    }
 3140
 3141    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3142        self.menu_edit_predictions_policy = value;
 3143    }
 3144
 3145    pub fn set_autoindent(&mut self, autoindent: bool) {
 3146        if autoindent {
 3147            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3148        } else {
 3149            self.autoindent_mode = None;
 3150        }
 3151    }
 3152
 3153    pub fn read_only(&self, cx: &App) -> bool {
 3154        self.read_only || self.buffer.read(cx).read_only()
 3155    }
 3156
 3157    pub fn set_read_only(&mut self, read_only: bool) {
 3158        self.read_only = read_only;
 3159    }
 3160
 3161    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3162        self.use_autoclose = autoclose;
 3163    }
 3164
 3165    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3166        self.use_auto_surround = auto_surround;
 3167    }
 3168
 3169    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3170        self.auto_replace_emoji_shortcode = auto_replace;
 3171    }
 3172
 3173    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3174        self.buffer_serialization = should_serialize.then(|| {
 3175            BufferSerialization::new(
 3176                ProjectSettings::get_global(cx)
 3177                    .session
 3178                    .restore_unsaved_buffers,
 3179            )
 3180        })
 3181    }
 3182
 3183    fn should_serialize_buffer(&self) -> bool {
 3184        self.buffer_serialization.is_some()
 3185    }
 3186
 3187    pub fn toggle_edit_predictions(
 3188        &mut self,
 3189        _: &ToggleEditPrediction,
 3190        window: &mut Window,
 3191        cx: &mut Context<Self>,
 3192    ) {
 3193        if self.show_edit_predictions_override.is_some() {
 3194            self.set_show_edit_predictions(None, window, cx);
 3195        } else {
 3196            let show_edit_predictions = !self.edit_predictions_enabled();
 3197            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3198        }
 3199    }
 3200
 3201    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3202        self.show_completions_on_input_override = show_completions_on_input;
 3203    }
 3204
 3205    pub fn set_show_edit_predictions(
 3206        &mut self,
 3207        show_edit_predictions: Option<bool>,
 3208        window: &mut Window,
 3209        cx: &mut Context<Self>,
 3210    ) {
 3211        self.show_edit_predictions_override = show_edit_predictions;
 3212        self.update_edit_prediction_settings(cx);
 3213
 3214        if let Some(false) = show_edit_predictions {
 3215            self.discard_edit_prediction(false, cx);
 3216        } else {
 3217            self.refresh_edit_prediction(false, true, window, cx);
 3218        }
 3219    }
 3220
 3221    fn edit_predictions_disabled_in_scope(
 3222        &self,
 3223        buffer: &Entity<Buffer>,
 3224        buffer_position: language::Anchor,
 3225        cx: &App,
 3226    ) -> bool {
 3227        let snapshot = buffer.read(cx).snapshot();
 3228        let settings = snapshot.settings_at(buffer_position, cx);
 3229
 3230        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3231            return false;
 3232        };
 3233
 3234        scope.override_name().is_some_and(|scope_name| {
 3235            settings
 3236                .edit_predictions_disabled_in
 3237                .iter()
 3238                .any(|s| s == scope_name)
 3239        })
 3240    }
 3241
 3242    pub fn set_use_modal_editing(&mut self, to: bool) {
 3243        self.use_modal_editing = to;
 3244    }
 3245
 3246    pub fn use_modal_editing(&self) -> bool {
 3247        self.use_modal_editing
 3248    }
 3249
 3250    fn selections_did_change(
 3251        &mut self,
 3252        local: bool,
 3253        old_cursor_position: &Anchor,
 3254        effects: SelectionEffects,
 3255        window: &mut Window,
 3256        cx: &mut Context<Self>,
 3257    ) {
 3258        window.invalidate_character_coordinates();
 3259
 3260        // Copy selections to primary selection buffer
 3261        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3262        if local {
 3263            let selections = self
 3264                .selections
 3265                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3266            let buffer_handle = self.buffer.read(cx).read(cx);
 3267
 3268            let mut text = String::new();
 3269            for (index, selection) in selections.iter().enumerate() {
 3270                let text_for_selection = buffer_handle
 3271                    .text_for_range(selection.start..selection.end)
 3272                    .collect::<String>();
 3273
 3274                text.push_str(&text_for_selection);
 3275                if index != selections.len() - 1 {
 3276                    text.push('\n');
 3277                }
 3278            }
 3279
 3280            if !text.is_empty() {
 3281                cx.write_to_primary(ClipboardItem::new_string(text));
 3282            }
 3283        }
 3284
 3285        let selection_anchors = self.selections.disjoint_anchors_arc();
 3286
 3287        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3288            self.buffer.update(cx, |buffer, cx| {
 3289                buffer.set_active_selections(
 3290                    &selection_anchors,
 3291                    self.selections.line_mode(),
 3292                    self.cursor_shape,
 3293                    cx,
 3294                )
 3295            });
 3296        }
 3297        let display_map = self
 3298            .display_map
 3299            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3300        let buffer = display_map.buffer_snapshot();
 3301        if self.selections.count() == 1 {
 3302            self.add_selections_state = None;
 3303        }
 3304        self.select_next_state = None;
 3305        self.select_prev_state = None;
 3306        self.select_syntax_node_history.try_clear();
 3307        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3308        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3309        self.take_rename(false, window, cx);
 3310
 3311        let newest_selection = self.selections.newest_anchor();
 3312        let new_cursor_position = newest_selection.head();
 3313        let selection_start = newest_selection.start;
 3314
 3315        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3316            self.push_to_nav_history(
 3317                *old_cursor_position,
 3318                Some(new_cursor_position.to_point(buffer)),
 3319                false,
 3320                effects.nav_history == Some(true),
 3321                cx,
 3322            );
 3323        }
 3324
 3325        if local {
 3326            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3327                self.register_buffer(buffer_id, cx);
 3328            }
 3329
 3330            let mut context_menu = self.context_menu.borrow_mut();
 3331            let completion_menu = match context_menu.as_ref() {
 3332                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3333                Some(CodeContextMenu::CodeActions(_)) => {
 3334                    *context_menu = None;
 3335                    None
 3336                }
 3337                None => None,
 3338            };
 3339            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3340            drop(context_menu);
 3341
 3342            if effects.completions
 3343                && let Some(completion_position) = completion_position
 3344            {
 3345                let start_offset = selection_start.to_offset(buffer);
 3346                let position_matches = start_offset == completion_position.to_offset(buffer);
 3347                let continue_showing = if position_matches {
 3348                    if self.snippet_stack.is_empty() {
 3349                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3350                            == Some(CharKind::Word)
 3351                    } else {
 3352                        // Snippet choices can be shown even when the cursor is in whitespace.
 3353                        // Dismissing the menu with actions like backspace is handled by
 3354                        // invalidation regions.
 3355                        true
 3356                    }
 3357                } else {
 3358                    false
 3359                };
 3360
 3361                if continue_showing {
 3362                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3363                } else {
 3364                    self.hide_context_menu(window, cx);
 3365                }
 3366            }
 3367
 3368            hide_hover(self, cx);
 3369
 3370            if old_cursor_position.to_display_point(&display_map).row()
 3371                != new_cursor_position.to_display_point(&display_map).row()
 3372            {
 3373                self.available_code_actions.take();
 3374            }
 3375            self.refresh_code_actions(window, cx);
 3376            self.refresh_document_highlights(cx);
 3377            refresh_linked_ranges(self, window, cx);
 3378
 3379            self.refresh_selected_text_highlights(false, window, cx);
 3380            self.refresh_matching_bracket_highlights(window, cx);
 3381            self.update_visible_edit_prediction(window, cx);
 3382            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3383            self.inline_blame_popover.take();
 3384            if self.git_blame_inline_enabled {
 3385                self.start_inline_blame_timer(window, cx);
 3386            }
 3387        }
 3388
 3389        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3390        cx.emit(EditorEvent::SelectionsChanged { local });
 3391
 3392        let selections = &self.selections.disjoint_anchors_arc();
 3393        if selections.len() == 1 {
 3394            cx.emit(SearchEvent::ActiveMatchChanged)
 3395        }
 3396        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3397            let inmemory_selections = selections
 3398                .iter()
 3399                .map(|s| {
 3400                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3401                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3402                })
 3403                .collect();
 3404            self.update_restoration_data(cx, |data| {
 3405                data.selections = inmemory_selections;
 3406            });
 3407
 3408            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3409                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3410            {
 3411                let snapshot = self.buffer().read(cx).snapshot(cx);
 3412                let selections = selections.clone();
 3413                let background_executor = cx.background_executor().clone();
 3414                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3415                self.serialize_selections = cx.background_spawn(async move {
 3416                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3417                    let db_selections = selections
 3418                        .iter()
 3419                        .map(|selection| {
 3420                            (
 3421                                selection.start.to_offset(&snapshot).0,
 3422                                selection.end.to_offset(&snapshot).0,
 3423                            )
 3424                        })
 3425                        .collect();
 3426
 3427                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3428                        .await
 3429                        .with_context(|| {
 3430                            format!(
 3431                                "persisting editor selections for editor {editor_id}, \
 3432                                workspace {workspace_id:?}"
 3433                            )
 3434                        })
 3435                        .log_err();
 3436                });
 3437            }
 3438        }
 3439
 3440        cx.notify();
 3441    }
 3442
 3443    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3444        use text::ToOffset as _;
 3445        use text::ToPoint as _;
 3446
 3447        if self.mode.is_minimap()
 3448            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3449        {
 3450            return;
 3451        }
 3452
 3453        if !self.buffer().read(cx).is_singleton() {
 3454            return;
 3455        }
 3456
 3457        let display_snapshot = self
 3458            .display_map
 3459            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3460        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3461            return;
 3462        };
 3463        let inmemory_folds = display_snapshot
 3464            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3465            .map(|fold| {
 3466                fold.range.start.text_anchor.to_point(&snapshot)
 3467                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3468            })
 3469            .collect();
 3470        self.update_restoration_data(cx, |data| {
 3471            data.folds = inmemory_folds;
 3472        });
 3473
 3474        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3475            return;
 3476        };
 3477        let background_executor = cx.background_executor().clone();
 3478        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3479        let db_folds = display_snapshot
 3480            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3481            .map(|fold| {
 3482                (
 3483                    fold.range.start.text_anchor.to_offset(&snapshot),
 3484                    fold.range.end.text_anchor.to_offset(&snapshot),
 3485                )
 3486            })
 3487            .collect();
 3488        self.serialize_folds = cx.background_spawn(async move {
 3489            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3490            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3491                .await
 3492                .with_context(|| {
 3493                    format!(
 3494                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3495                    )
 3496                })
 3497                .log_err();
 3498        });
 3499    }
 3500
 3501    pub fn sync_selections(
 3502        &mut self,
 3503        other: Entity<Editor>,
 3504        cx: &mut Context<Self>,
 3505    ) -> gpui::Subscription {
 3506        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3507        if !other_selections.is_empty() {
 3508            self.selections
 3509                .change_with(&self.display_snapshot(cx), |selections| {
 3510                    selections.select_anchors(other_selections);
 3511                });
 3512        }
 3513
 3514        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3515            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3516                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3517                if other_selections.is_empty() {
 3518                    return;
 3519                }
 3520                let snapshot = this.display_snapshot(cx);
 3521                this.selections.change_with(&snapshot, |selections| {
 3522                    selections.select_anchors(other_selections);
 3523                });
 3524            }
 3525        });
 3526
 3527        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3528            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3529                let these_selections = this.selections.disjoint_anchors().to_vec();
 3530                if these_selections.is_empty() {
 3531                    return;
 3532                }
 3533                other.update(cx, |other_editor, cx| {
 3534                    let snapshot = other_editor.display_snapshot(cx);
 3535                    other_editor
 3536                        .selections
 3537                        .change_with(&snapshot, |selections| {
 3538                            selections.select_anchors(these_selections);
 3539                        })
 3540                });
 3541            }
 3542        });
 3543
 3544        Subscription::join(other_subscription, this_subscription)
 3545    }
 3546
 3547    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3548        if self.buffer().read(cx).is_singleton() {
 3549            return;
 3550        }
 3551        let snapshot = self.buffer.read(cx).snapshot(cx);
 3552        let buffer_ids: HashSet<BufferId> = self
 3553            .selections
 3554            .disjoint_anchor_ranges()
 3555            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3556            .collect();
 3557        for buffer_id in buffer_ids {
 3558            self.unfold_buffer(buffer_id, cx);
 3559        }
 3560    }
 3561
 3562    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3563    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3564    /// effects of selection change occur at the end of the transaction.
 3565    pub fn change_selections<R>(
 3566        &mut self,
 3567        effects: SelectionEffects,
 3568        window: &mut Window,
 3569        cx: &mut Context<Self>,
 3570        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3571    ) -> R {
 3572        let snapshot = self.display_snapshot(cx);
 3573        if let Some(state) = &mut self.deferred_selection_effects_state {
 3574            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3575            state.effects.completions = effects.completions;
 3576            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3577            let (changed, result) = self.selections.change_with(&snapshot, change);
 3578            state.changed |= changed;
 3579            return result;
 3580        }
 3581        let mut state = DeferredSelectionEffectsState {
 3582            changed: false,
 3583            effects,
 3584            old_cursor_position: self.selections.newest_anchor().head(),
 3585            history_entry: SelectionHistoryEntry {
 3586                selections: self.selections.disjoint_anchors_arc(),
 3587                select_next_state: self.select_next_state.clone(),
 3588                select_prev_state: self.select_prev_state.clone(),
 3589                add_selections_state: self.add_selections_state.clone(),
 3590            },
 3591        };
 3592        let (changed, result) = self.selections.change_with(&snapshot, change);
 3593        state.changed = state.changed || changed;
 3594        if self.defer_selection_effects {
 3595            self.deferred_selection_effects_state = Some(state);
 3596        } else {
 3597            self.apply_selection_effects(state, window, cx);
 3598        }
 3599        result
 3600    }
 3601
 3602    /// Defers the effects of selection change, so that the effects of multiple calls to
 3603    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3604    /// to selection history and the state of popovers based on selection position aren't
 3605    /// erroneously updated.
 3606    pub fn with_selection_effects_deferred<R>(
 3607        &mut self,
 3608        window: &mut Window,
 3609        cx: &mut Context<Self>,
 3610        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3611    ) -> R {
 3612        let already_deferred = self.defer_selection_effects;
 3613        self.defer_selection_effects = true;
 3614        let result = update(self, window, cx);
 3615        if !already_deferred {
 3616            self.defer_selection_effects = false;
 3617            if let Some(state) = self.deferred_selection_effects_state.take() {
 3618                self.apply_selection_effects(state, window, cx);
 3619            }
 3620        }
 3621        result
 3622    }
 3623
 3624    fn apply_selection_effects(
 3625        &mut self,
 3626        state: DeferredSelectionEffectsState,
 3627        window: &mut Window,
 3628        cx: &mut Context<Self>,
 3629    ) {
 3630        if state.changed {
 3631            self.selection_history.push(state.history_entry);
 3632
 3633            if let Some(autoscroll) = state.effects.scroll {
 3634                self.request_autoscroll(autoscroll, cx);
 3635            }
 3636
 3637            let old_cursor_position = &state.old_cursor_position;
 3638
 3639            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3640
 3641            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3642                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3643            }
 3644        }
 3645    }
 3646
 3647    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3648    where
 3649        I: IntoIterator<Item = (Range<S>, T)>,
 3650        S: ToOffset,
 3651        T: Into<Arc<str>>,
 3652    {
 3653        if self.read_only(cx) {
 3654            return;
 3655        }
 3656
 3657        self.buffer
 3658            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3659    }
 3660
 3661    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3662    where
 3663        I: IntoIterator<Item = (Range<S>, T)>,
 3664        S: ToOffset,
 3665        T: Into<Arc<str>>,
 3666    {
 3667        if self.read_only(cx) {
 3668            return;
 3669        }
 3670
 3671        self.buffer.update(cx, |buffer, cx| {
 3672            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3673        });
 3674    }
 3675
 3676    pub fn edit_with_block_indent<I, S, T>(
 3677        &mut self,
 3678        edits: I,
 3679        original_indent_columns: Vec<Option<u32>>,
 3680        cx: &mut Context<Self>,
 3681    ) where
 3682        I: IntoIterator<Item = (Range<S>, T)>,
 3683        S: ToOffset,
 3684        T: Into<Arc<str>>,
 3685    {
 3686        if self.read_only(cx) {
 3687            return;
 3688        }
 3689
 3690        self.buffer.update(cx, |buffer, cx| {
 3691            buffer.edit(
 3692                edits,
 3693                Some(AutoindentMode::Block {
 3694                    original_indent_columns,
 3695                }),
 3696                cx,
 3697            )
 3698        });
 3699    }
 3700
 3701    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3702        self.hide_context_menu(window, cx);
 3703
 3704        match phase {
 3705            SelectPhase::Begin {
 3706                position,
 3707                add,
 3708                click_count,
 3709            } => self.begin_selection(position, add, click_count, window, cx),
 3710            SelectPhase::BeginColumnar {
 3711                position,
 3712                goal_column,
 3713                reset,
 3714                mode,
 3715            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3716            SelectPhase::Extend {
 3717                position,
 3718                click_count,
 3719            } => self.extend_selection(position, click_count, window, cx),
 3720            SelectPhase::Update {
 3721                position,
 3722                goal_column,
 3723                scroll_delta,
 3724            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3725            SelectPhase::End => self.end_selection(window, cx),
 3726        }
 3727    }
 3728
 3729    fn extend_selection(
 3730        &mut self,
 3731        position: DisplayPoint,
 3732        click_count: usize,
 3733        window: &mut Window,
 3734        cx: &mut Context<Self>,
 3735    ) {
 3736        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3737        let tail = self
 3738            .selections
 3739            .newest::<MultiBufferOffset>(&display_map)
 3740            .tail();
 3741        let click_count = click_count.max(match self.selections.select_mode() {
 3742            SelectMode::Character => 1,
 3743            SelectMode::Word(_) => 2,
 3744            SelectMode::Line(_) => 3,
 3745            SelectMode::All => 4,
 3746        });
 3747        self.begin_selection(position, false, click_count, window, cx);
 3748
 3749        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3750
 3751        let current_selection = match self.selections.select_mode() {
 3752            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3753            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3754        };
 3755
 3756        let mut pending_selection = self
 3757            .selections
 3758            .pending_anchor()
 3759            .cloned()
 3760            .expect("extend_selection not called with pending selection");
 3761
 3762        if pending_selection
 3763            .start
 3764            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3765            == Ordering::Greater
 3766        {
 3767            pending_selection.start = current_selection.start;
 3768        }
 3769        if pending_selection
 3770            .end
 3771            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3772            == Ordering::Less
 3773        {
 3774            pending_selection.end = current_selection.end;
 3775            pending_selection.reversed = true;
 3776        }
 3777
 3778        let mut pending_mode = self.selections.pending_mode().unwrap();
 3779        match &mut pending_mode {
 3780            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3781            _ => {}
 3782        }
 3783
 3784        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3785            SelectionEffects::scroll(Autoscroll::fit())
 3786        } else {
 3787            SelectionEffects::no_scroll()
 3788        };
 3789
 3790        self.change_selections(effects, window, cx, |s| {
 3791            s.set_pending(pending_selection.clone(), pending_mode);
 3792            s.set_is_extending(true);
 3793        });
 3794    }
 3795
 3796    fn begin_selection(
 3797        &mut self,
 3798        position: DisplayPoint,
 3799        add: bool,
 3800        click_count: usize,
 3801        window: &mut Window,
 3802        cx: &mut Context<Self>,
 3803    ) {
 3804        if !self.focus_handle.is_focused(window) {
 3805            self.last_focused_descendant = None;
 3806            window.focus(&self.focus_handle);
 3807        }
 3808
 3809        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3810        let buffer = display_map.buffer_snapshot();
 3811        let position = display_map.clip_point(position, Bias::Left);
 3812
 3813        let start;
 3814        let end;
 3815        let mode;
 3816        let mut auto_scroll;
 3817        match click_count {
 3818            1 => {
 3819                start = buffer.anchor_before(position.to_point(&display_map));
 3820                end = start;
 3821                mode = SelectMode::Character;
 3822                auto_scroll = true;
 3823            }
 3824            2 => {
 3825                let position = display_map
 3826                    .clip_point(position, Bias::Left)
 3827                    .to_offset(&display_map, Bias::Left);
 3828                let (range, _) = buffer.surrounding_word(position, None);
 3829                start = buffer.anchor_before(range.start);
 3830                end = buffer.anchor_before(range.end);
 3831                mode = SelectMode::Word(start..end);
 3832                auto_scroll = true;
 3833            }
 3834            3 => {
 3835                let position = display_map
 3836                    .clip_point(position, Bias::Left)
 3837                    .to_point(&display_map);
 3838                let line_start = display_map.prev_line_boundary(position).0;
 3839                let next_line_start = buffer.clip_point(
 3840                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3841                    Bias::Left,
 3842                );
 3843                start = buffer.anchor_before(line_start);
 3844                end = buffer.anchor_before(next_line_start);
 3845                mode = SelectMode::Line(start..end);
 3846                auto_scroll = true;
 3847            }
 3848            _ => {
 3849                start = buffer.anchor_before(MultiBufferOffset(0));
 3850                end = buffer.anchor_before(buffer.len());
 3851                mode = SelectMode::All;
 3852                auto_scroll = false;
 3853            }
 3854        }
 3855        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3856
 3857        let point_to_delete: Option<usize> = {
 3858            let selected_points: Vec<Selection<Point>> =
 3859                self.selections.disjoint_in_range(start..end, &display_map);
 3860
 3861            if !add || click_count > 1 {
 3862                None
 3863            } else if !selected_points.is_empty() {
 3864                Some(selected_points[0].id)
 3865            } else {
 3866                let clicked_point_already_selected =
 3867                    self.selections.disjoint_anchors().iter().find(|selection| {
 3868                        selection.start.to_point(buffer) == start.to_point(buffer)
 3869                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3870                    });
 3871
 3872                clicked_point_already_selected.map(|selection| selection.id)
 3873            }
 3874        };
 3875
 3876        let selections_count = self.selections.count();
 3877        let effects = if auto_scroll {
 3878            SelectionEffects::default()
 3879        } else {
 3880            SelectionEffects::no_scroll()
 3881        };
 3882
 3883        self.change_selections(effects, window, cx, |s| {
 3884            if let Some(point_to_delete) = point_to_delete {
 3885                s.delete(point_to_delete);
 3886
 3887                if selections_count == 1 {
 3888                    s.set_pending_anchor_range(start..end, mode);
 3889                }
 3890            } else {
 3891                if !add {
 3892                    s.clear_disjoint();
 3893                }
 3894
 3895                s.set_pending_anchor_range(start..end, mode);
 3896            }
 3897        });
 3898    }
 3899
 3900    fn begin_columnar_selection(
 3901        &mut self,
 3902        position: DisplayPoint,
 3903        goal_column: u32,
 3904        reset: bool,
 3905        mode: ColumnarMode,
 3906        window: &mut Window,
 3907        cx: &mut Context<Self>,
 3908    ) {
 3909        if !self.focus_handle.is_focused(window) {
 3910            self.last_focused_descendant = None;
 3911            window.focus(&self.focus_handle);
 3912        }
 3913
 3914        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3915
 3916        if reset {
 3917            let pointer_position = display_map
 3918                .buffer_snapshot()
 3919                .anchor_before(position.to_point(&display_map));
 3920
 3921            self.change_selections(
 3922                SelectionEffects::scroll(Autoscroll::newest()),
 3923                window,
 3924                cx,
 3925                |s| {
 3926                    s.clear_disjoint();
 3927                    s.set_pending_anchor_range(
 3928                        pointer_position..pointer_position,
 3929                        SelectMode::Character,
 3930                    );
 3931                },
 3932            );
 3933        };
 3934
 3935        let tail = self.selections.newest::<Point>(&display_map).tail();
 3936        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3937        self.columnar_selection_state = match mode {
 3938            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3939                selection_tail: selection_anchor,
 3940                display_point: if reset {
 3941                    if position.column() != goal_column {
 3942                        Some(DisplayPoint::new(position.row(), goal_column))
 3943                    } else {
 3944                        None
 3945                    }
 3946                } else {
 3947                    None
 3948                },
 3949            }),
 3950            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3951                selection_tail: selection_anchor,
 3952            }),
 3953        };
 3954
 3955        if !reset {
 3956            self.select_columns(position, goal_column, &display_map, window, cx);
 3957        }
 3958    }
 3959
 3960    fn update_selection(
 3961        &mut self,
 3962        position: DisplayPoint,
 3963        goal_column: u32,
 3964        scroll_delta: gpui::Point<f32>,
 3965        window: &mut Window,
 3966        cx: &mut Context<Self>,
 3967    ) {
 3968        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3969
 3970        if self.columnar_selection_state.is_some() {
 3971            self.select_columns(position, goal_column, &display_map, window, cx);
 3972        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3973            let buffer = display_map.buffer_snapshot();
 3974            let head;
 3975            let tail;
 3976            let mode = self.selections.pending_mode().unwrap();
 3977            match &mode {
 3978                SelectMode::Character => {
 3979                    head = position.to_point(&display_map);
 3980                    tail = pending.tail().to_point(buffer);
 3981                }
 3982                SelectMode::Word(original_range) => {
 3983                    let offset = display_map
 3984                        .clip_point(position, Bias::Left)
 3985                        .to_offset(&display_map, Bias::Left);
 3986                    let original_range = original_range.to_offset(buffer);
 3987
 3988                    let head_offset = if buffer.is_inside_word(offset, None)
 3989                        || original_range.contains(&offset)
 3990                    {
 3991                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3992                        if word_range.start < original_range.start {
 3993                            word_range.start
 3994                        } else {
 3995                            word_range.end
 3996                        }
 3997                    } else {
 3998                        offset
 3999                    };
 4000
 4001                    head = head_offset.to_point(buffer);
 4002                    if head_offset <= original_range.start {
 4003                        tail = original_range.end.to_point(buffer);
 4004                    } else {
 4005                        tail = original_range.start.to_point(buffer);
 4006                    }
 4007                }
 4008                SelectMode::Line(original_range) => {
 4009                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4010
 4011                    let position = display_map
 4012                        .clip_point(position, Bias::Left)
 4013                        .to_point(&display_map);
 4014                    let line_start = display_map.prev_line_boundary(position).0;
 4015                    let next_line_start = buffer.clip_point(
 4016                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4017                        Bias::Left,
 4018                    );
 4019
 4020                    if line_start < original_range.start {
 4021                        head = line_start
 4022                    } else {
 4023                        head = next_line_start
 4024                    }
 4025
 4026                    if head <= original_range.start {
 4027                        tail = original_range.end;
 4028                    } else {
 4029                        tail = original_range.start;
 4030                    }
 4031                }
 4032                SelectMode::All => {
 4033                    return;
 4034                }
 4035            };
 4036
 4037            if head < tail {
 4038                pending.start = buffer.anchor_before(head);
 4039                pending.end = buffer.anchor_before(tail);
 4040                pending.reversed = true;
 4041            } else {
 4042                pending.start = buffer.anchor_before(tail);
 4043                pending.end = buffer.anchor_before(head);
 4044                pending.reversed = false;
 4045            }
 4046
 4047            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4048                s.set_pending(pending.clone(), mode);
 4049            });
 4050        } else {
 4051            log::error!("update_selection dispatched with no pending selection");
 4052            return;
 4053        }
 4054
 4055        self.apply_scroll_delta(scroll_delta, window, cx);
 4056        cx.notify();
 4057    }
 4058
 4059    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4060        self.columnar_selection_state.take();
 4061        if let Some(pending_mode) = self.selections.pending_mode() {
 4062            let selections = self
 4063                .selections
 4064                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4065            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4066                s.select(selections);
 4067                s.clear_pending();
 4068                if s.is_extending() {
 4069                    s.set_is_extending(false);
 4070                } else {
 4071                    s.set_select_mode(pending_mode);
 4072                }
 4073            });
 4074        }
 4075    }
 4076
 4077    fn select_columns(
 4078        &mut self,
 4079        head: DisplayPoint,
 4080        goal_column: u32,
 4081        display_map: &DisplaySnapshot,
 4082        window: &mut Window,
 4083        cx: &mut Context<Self>,
 4084    ) {
 4085        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4086            return;
 4087        };
 4088
 4089        let tail = match columnar_state {
 4090            ColumnarSelectionState::FromMouse {
 4091                selection_tail,
 4092                display_point,
 4093            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4094            ColumnarSelectionState::FromSelection { selection_tail } => {
 4095                selection_tail.to_display_point(display_map)
 4096            }
 4097        };
 4098
 4099        let start_row = cmp::min(tail.row(), head.row());
 4100        let end_row = cmp::max(tail.row(), head.row());
 4101        let start_column = cmp::min(tail.column(), goal_column);
 4102        let end_column = cmp::max(tail.column(), goal_column);
 4103        let reversed = start_column < tail.column();
 4104
 4105        let selection_ranges = (start_row.0..=end_row.0)
 4106            .map(DisplayRow)
 4107            .filter_map(|row| {
 4108                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4109                    || start_column <= display_map.line_len(row))
 4110                    && !display_map.is_block_line(row)
 4111                {
 4112                    let start = display_map
 4113                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4114                        .to_point(display_map);
 4115                    let end = display_map
 4116                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4117                        .to_point(display_map);
 4118                    if reversed {
 4119                        Some(end..start)
 4120                    } else {
 4121                        Some(start..end)
 4122                    }
 4123                } else {
 4124                    None
 4125                }
 4126            })
 4127            .collect::<Vec<_>>();
 4128        if selection_ranges.is_empty() {
 4129            return;
 4130        }
 4131
 4132        let ranges = match columnar_state {
 4133            ColumnarSelectionState::FromMouse { .. } => {
 4134                let mut non_empty_ranges = selection_ranges
 4135                    .iter()
 4136                    .filter(|selection_range| selection_range.start != selection_range.end)
 4137                    .peekable();
 4138                if non_empty_ranges.peek().is_some() {
 4139                    non_empty_ranges.cloned().collect()
 4140                } else {
 4141                    selection_ranges
 4142                }
 4143            }
 4144            _ => selection_ranges,
 4145        };
 4146
 4147        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4148            s.select_ranges(ranges);
 4149        });
 4150        cx.notify();
 4151    }
 4152
 4153    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4154        self.selections
 4155            .all_adjusted(snapshot)
 4156            .iter()
 4157            .any(|selection| !selection.is_empty())
 4158    }
 4159
 4160    pub fn has_pending_nonempty_selection(&self) -> bool {
 4161        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4162            Some(Selection { start, end, .. }) => start != end,
 4163            None => false,
 4164        };
 4165
 4166        pending_nonempty_selection
 4167            || (self.columnar_selection_state.is_some()
 4168                && self.selections.disjoint_anchors().len() > 1)
 4169    }
 4170
 4171    pub fn has_pending_selection(&self) -> bool {
 4172        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4173    }
 4174
 4175    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4176        self.selection_mark_mode = false;
 4177        self.selection_drag_state = SelectionDragState::None;
 4178
 4179        if self.dismiss_menus_and_popups(true, window, cx) {
 4180            cx.notify();
 4181            return;
 4182        }
 4183        if self.clear_expanded_diff_hunks(cx) {
 4184            cx.notify();
 4185            return;
 4186        }
 4187        if self.show_git_blame_gutter {
 4188            self.show_git_blame_gutter = false;
 4189            cx.notify();
 4190            return;
 4191        }
 4192
 4193        if self.mode.is_full()
 4194            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4195        {
 4196            cx.notify();
 4197            return;
 4198        }
 4199
 4200        cx.propagate();
 4201    }
 4202
 4203    pub fn dismiss_menus_and_popups(
 4204        &mut self,
 4205        is_user_requested: bool,
 4206        window: &mut Window,
 4207        cx: &mut Context<Self>,
 4208    ) -> bool {
 4209        let mut dismissed = false;
 4210
 4211        dismissed |= self.take_rename(false, window, cx).is_some();
 4212        dismissed |= self.hide_blame_popover(true, cx);
 4213        dismissed |= hide_hover(self, cx);
 4214        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4215        dismissed |= self.hide_context_menu(window, cx).is_some();
 4216        dismissed |= self.mouse_context_menu.take().is_some();
 4217        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4218        dismissed |= self.snippet_stack.pop().is_some();
 4219
 4220        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4221            self.dismiss_diagnostics(cx);
 4222            dismissed = true;
 4223        }
 4224
 4225        dismissed
 4226    }
 4227
 4228    fn linked_editing_ranges_for(
 4229        &self,
 4230        selection: Range<text::Anchor>,
 4231        cx: &App,
 4232    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4233        if self.linked_edit_ranges.is_empty() {
 4234            return None;
 4235        }
 4236        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4237            selection.end.buffer_id.and_then(|end_buffer_id| {
 4238                if selection.start.buffer_id != Some(end_buffer_id) {
 4239                    return None;
 4240                }
 4241                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4242                let snapshot = buffer.read(cx).snapshot();
 4243                self.linked_edit_ranges
 4244                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4245                    .map(|ranges| (ranges, snapshot, buffer))
 4246            })?;
 4247        use text::ToOffset as TO;
 4248        // find offset from the start of current range to current cursor position
 4249        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4250
 4251        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4252        let start_difference = start_offset - start_byte_offset;
 4253        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4254        let end_difference = end_offset - start_byte_offset;
 4255        // Current range has associated linked ranges.
 4256        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4257        for range in linked_ranges.iter() {
 4258            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4259            let end_offset = start_offset + end_difference;
 4260            let start_offset = start_offset + start_difference;
 4261            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4262                continue;
 4263            }
 4264            if self.selections.disjoint_anchor_ranges().any(|s| {
 4265                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4266                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4267                {
 4268                    return false;
 4269                }
 4270                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4271                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4272            }) {
 4273                continue;
 4274            }
 4275            let start = buffer_snapshot.anchor_after(start_offset);
 4276            let end = buffer_snapshot.anchor_after(end_offset);
 4277            linked_edits
 4278                .entry(buffer.clone())
 4279                .or_default()
 4280                .push(start..end);
 4281        }
 4282        Some(linked_edits)
 4283    }
 4284
 4285    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4286        let text: Arc<str> = text.into();
 4287
 4288        if self.read_only(cx) {
 4289            return;
 4290        }
 4291
 4292        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4293
 4294        self.unfold_buffers_with_selections(cx);
 4295
 4296        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4297        let mut bracket_inserted = false;
 4298        let mut edits = Vec::new();
 4299        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4300        let mut new_selections = Vec::with_capacity(selections.len());
 4301        let mut new_autoclose_regions = Vec::new();
 4302        let snapshot = self.buffer.read(cx).read(cx);
 4303        let mut clear_linked_edit_ranges = false;
 4304
 4305        for (selection, autoclose_region) in
 4306            self.selections_with_autoclose_regions(selections, &snapshot)
 4307        {
 4308            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4309                // Determine if the inserted text matches the opening or closing
 4310                // bracket of any of this language's bracket pairs.
 4311                let mut bracket_pair = None;
 4312                let mut is_bracket_pair_start = false;
 4313                let mut is_bracket_pair_end = false;
 4314                if !text.is_empty() {
 4315                    let mut bracket_pair_matching_end = None;
 4316                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4317                    //  and they are removing the character that triggered IME popup.
 4318                    for (pair, enabled) in scope.brackets() {
 4319                        if !pair.close && !pair.surround {
 4320                            continue;
 4321                        }
 4322
 4323                        if enabled && pair.start.ends_with(text.as_ref()) {
 4324                            let prefix_len = pair.start.len() - text.len();
 4325                            let preceding_text_matches_prefix = prefix_len == 0
 4326                                || (selection.start.column >= (prefix_len as u32)
 4327                                    && snapshot.contains_str_at(
 4328                                        Point::new(
 4329                                            selection.start.row,
 4330                                            selection.start.column - (prefix_len as u32),
 4331                                        ),
 4332                                        &pair.start[..prefix_len],
 4333                                    ));
 4334                            if preceding_text_matches_prefix {
 4335                                bracket_pair = Some(pair.clone());
 4336                                is_bracket_pair_start = true;
 4337                                break;
 4338                            }
 4339                        }
 4340                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4341                        {
 4342                            // take first bracket pair matching end, but don't break in case a later bracket
 4343                            // pair matches start
 4344                            bracket_pair_matching_end = Some(pair.clone());
 4345                        }
 4346                    }
 4347                    if let Some(end) = bracket_pair_matching_end
 4348                        && bracket_pair.is_none()
 4349                    {
 4350                        bracket_pair = Some(end);
 4351                        is_bracket_pair_end = true;
 4352                    }
 4353                }
 4354
 4355                if let Some(bracket_pair) = bracket_pair {
 4356                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4357                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4358                    let auto_surround =
 4359                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4360                    if selection.is_empty() {
 4361                        if is_bracket_pair_start {
 4362                            // If the inserted text is a suffix of an opening bracket and the
 4363                            // selection is preceded by the rest of the opening bracket, then
 4364                            // insert the closing bracket.
 4365                            let following_text_allows_autoclose = snapshot
 4366                                .chars_at(selection.start)
 4367                                .next()
 4368                                .is_none_or(|c| scope.should_autoclose_before(c));
 4369
 4370                            let preceding_text_allows_autoclose = selection.start.column == 0
 4371                                || snapshot
 4372                                    .reversed_chars_at(selection.start)
 4373                                    .next()
 4374                                    .is_none_or(|c| {
 4375                                        bracket_pair.start != bracket_pair.end
 4376                                            || !snapshot
 4377                                                .char_classifier_at(selection.start)
 4378                                                .is_word(c)
 4379                                    });
 4380
 4381                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4382                                && bracket_pair.start.len() == 1
 4383                            {
 4384                                let target = bracket_pair.start.chars().next().unwrap();
 4385                                let current_line_count = snapshot
 4386                                    .reversed_chars_at(selection.start)
 4387                                    .take_while(|&c| c != '\n')
 4388                                    .filter(|&c| c == target)
 4389                                    .count();
 4390                                current_line_count % 2 == 1
 4391                            } else {
 4392                                false
 4393                            };
 4394
 4395                            if autoclose
 4396                                && bracket_pair.close
 4397                                && following_text_allows_autoclose
 4398                                && preceding_text_allows_autoclose
 4399                                && !is_closing_quote
 4400                            {
 4401                                let anchor = snapshot.anchor_before(selection.end);
 4402                                new_selections.push((selection.map(|_| anchor), text.len()));
 4403                                new_autoclose_regions.push((
 4404                                    anchor,
 4405                                    text.len(),
 4406                                    selection.id,
 4407                                    bracket_pair.clone(),
 4408                                ));
 4409                                edits.push((
 4410                                    selection.range(),
 4411                                    format!("{}{}", text, bracket_pair.end).into(),
 4412                                ));
 4413                                bracket_inserted = true;
 4414                                continue;
 4415                            }
 4416                        }
 4417
 4418                        if let Some(region) = autoclose_region {
 4419                            // If the selection is followed by an auto-inserted closing bracket,
 4420                            // then don't insert that closing bracket again; just move the selection
 4421                            // past the closing bracket.
 4422                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4423                                && text.as_ref() == region.pair.end.as_str()
 4424                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4425                            if should_skip {
 4426                                let anchor = snapshot.anchor_after(selection.end);
 4427                                new_selections
 4428                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4429                                continue;
 4430                            }
 4431                        }
 4432
 4433                        let always_treat_brackets_as_autoclosed = snapshot
 4434                            .language_settings_at(selection.start, cx)
 4435                            .always_treat_brackets_as_autoclosed;
 4436                        if always_treat_brackets_as_autoclosed
 4437                            && is_bracket_pair_end
 4438                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4439                        {
 4440                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4441                            // and the inserted text is a closing bracket and the selection is followed
 4442                            // by the closing bracket then move the selection past the closing bracket.
 4443                            let anchor = snapshot.anchor_after(selection.end);
 4444                            new_selections.push((selection.map(|_| anchor), text.len()));
 4445                            continue;
 4446                        }
 4447                    }
 4448                    // If an opening bracket is 1 character long and is typed while
 4449                    // text is selected, then surround that text with the bracket pair.
 4450                    else if auto_surround
 4451                        && bracket_pair.surround
 4452                        && is_bracket_pair_start
 4453                        && bracket_pair.start.chars().count() == 1
 4454                    {
 4455                        edits.push((selection.start..selection.start, text.clone()));
 4456                        edits.push((
 4457                            selection.end..selection.end,
 4458                            bracket_pair.end.as_str().into(),
 4459                        ));
 4460                        bracket_inserted = true;
 4461                        new_selections.push((
 4462                            Selection {
 4463                                id: selection.id,
 4464                                start: snapshot.anchor_after(selection.start),
 4465                                end: snapshot.anchor_before(selection.end),
 4466                                reversed: selection.reversed,
 4467                                goal: selection.goal,
 4468                            },
 4469                            0,
 4470                        ));
 4471                        continue;
 4472                    }
 4473                }
 4474            }
 4475
 4476            if self.auto_replace_emoji_shortcode
 4477                && selection.is_empty()
 4478                && text.as_ref().ends_with(':')
 4479                && let Some(possible_emoji_short_code) =
 4480                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4481                && !possible_emoji_short_code.is_empty()
 4482                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4483            {
 4484                let emoji_shortcode_start = Point::new(
 4485                    selection.start.row,
 4486                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4487                );
 4488
 4489                // Remove shortcode from buffer
 4490                edits.push((
 4491                    emoji_shortcode_start..selection.start,
 4492                    "".to_string().into(),
 4493                ));
 4494                new_selections.push((
 4495                    Selection {
 4496                        id: selection.id,
 4497                        start: snapshot.anchor_after(emoji_shortcode_start),
 4498                        end: snapshot.anchor_before(selection.start),
 4499                        reversed: selection.reversed,
 4500                        goal: selection.goal,
 4501                    },
 4502                    0,
 4503                ));
 4504
 4505                // Insert emoji
 4506                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4507                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4508                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4509
 4510                continue;
 4511            }
 4512
 4513            // If not handling any auto-close operation, then just replace the selected
 4514            // text with the given input and move the selection to the end of the
 4515            // newly inserted text.
 4516            let anchor = snapshot.anchor_after(selection.end);
 4517            if !self.linked_edit_ranges.is_empty() {
 4518                let start_anchor = snapshot.anchor_before(selection.start);
 4519
 4520                let is_word_char = text.chars().next().is_none_or(|char| {
 4521                    let classifier = snapshot
 4522                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4523                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4524                    classifier.is_word(char)
 4525                });
 4526
 4527                if is_word_char {
 4528                    if let Some(ranges) = self
 4529                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4530                    {
 4531                        for (buffer, edits) in ranges {
 4532                            linked_edits
 4533                                .entry(buffer.clone())
 4534                                .or_default()
 4535                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4536                        }
 4537                    }
 4538                } else {
 4539                    clear_linked_edit_ranges = true;
 4540                }
 4541            }
 4542
 4543            new_selections.push((selection.map(|_| anchor), 0));
 4544            edits.push((selection.start..selection.end, text.clone()));
 4545        }
 4546
 4547        drop(snapshot);
 4548
 4549        self.transact(window, cx, |this, window, cx| {
 4550            if clear_linked_edit_ranges {
 4551                this.linked_edit_ranges.clear();
 4552            }
 4553            let initial_buffer_versions =
 4554                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4555
 4556            this.buffer.update(cx, |buffer, cx| {
 4557                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4558            });
 4559            for (buffer, edits) in linked_edits {
 4560                buffer.update(cx, |buffer, cx| {
 4561                    let snapshot = buffer.snapshot();
 4562                    let edits = edits
 4563                        .into_iter()
 4564                        .map(|(range, text)| {
 4565                            use text::ToPoint as TP;
 4566                            let end_point = TP::to_point(&range.end, &snapshot);
 4567                            let start_point = TP::to_point(&range.start, &snapshot);
 4568                            (start_point..end_point, text)
 4569                        })
 4570                        .sorted_by_key(|(range, _)| range.start);
 4571                    buffer.edit(edits, None, cx);
 4572                })
 4573            }
 4574            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4575            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4576            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4577            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4578                new_anchor_selections,
 4579                &map,
 4580            )
 4581            .zip(new_selection_deltas)
 4582            .map(|(selection, delta)| Selection {
 4583                id: selection.id,
 4584                start: selection.start + delta,
 4585                end: selection.end + delta,
 4586                reversed: selection.reversed,
 4587                goal: SelectionGoal::None,
 4588            })
 4589            .collect::<Vec<_>>();
 4590
 4591            let mut i = 0;
 4592            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4593                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4594                let start = map.buffer_snapshot().anchor_before(position);
 4595                let end = map.buffer_snapshot().anchor_after(position);
 4596                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4597                    match existing_state
 4598                        .range
 4599                        .start
 4600                        .cmp(&start, map.buffer_snapshot())
 4601                    {
 4602                        Ordering::Less => i += 1,
 4603                        Ordering::Greater => break,
 4604                        Ordering::Equal => {
 4605                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4606                                Ordering::Less => i += 1,
 4607                                Ordering::Equal => break,
 4608                                Ordering::Greater => break,
 4609                            }
 4610                        }
 4611                    }
 4612                }
 4613                this.autoclose_regions.insert(
 4614                    i,
 4615                    AutocloseRegion {
 4616                        selection_id,
 4617                        range: start..end,
 4618                        pair,
 4619                    },
 4620                );
 4621            }
 4622
 4623            let had_active_edit_prediction = this.has_active_edit_prediction();
 4624            this.change_selections(
 4625                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4626                window,
 4627                cx,
 4628                |s| s.select(new_selections),
 4629            );
 4630
 4631            if !bracket_inserted
 4632                && let Some(on_type_format_task) =
 4633                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4634            {
 4635                on_type_format_task.detach_and_log_err(cx);
 4636            }
 4637
 4638            let editor_settings = EditorSettings::get_global(cx);
 4639            if bracket_inserted
 4640                && (editor_settings.auto_signature_help
 4641                    || editor_settings.show_signature_help_after_edits)
 4642            {
 4643                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4644            }
 4645
 4646            let trigger_in_words =
 4647                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4648            if this.hard_wrap.is_some() {
 4649                let latest: Range<Point> = this.selections.newest(&map).range();
 4650                if latest.is_empty()
 4651                    && this
 4652                        .buffer()
 4653                        .read(cx)
 4654                        .snapshot(cx)
 4655                        .line_len(MultiBufferRow(latest.start.row))
 4656                        == latest.start.column
 4657                {
 4658                    this.rewrap_impl(
 4659                        RewrapOptions {
 4660                            override_language_settings: true,
 4661                            preserve_existing_whitespace: true,
 4662                        },
 4663                        cx,
 4664                    )
 4665                }
 4666            }
 4667            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4668            refresh_linked_ranges(this, window, cx);
 4669            this.refresh_edit_prediction(true, false, window, cx);
 4670            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4671        });
 4672    }
 4673
 4674    fn find_possible_emoji_shortcode_at_position(
 4675        snapshot: &MultiBufferSnapshot,
 4676        position: Point,
 4677    ) -> Option<String> {
 4678        let mut chars = Vec::new();
 4679        let mut found_colon = false;
 4680        for char in snapshot.reversed_chars_at(position).take(100) {
 4681            // Found a possible emoji shortcode in the middle of the buffer
 4682            if found_colon {
 4683                if char.is_whitespace() {
 4684                    chars.reverse();
 4685                    return Some(chars.iter().collect());
 4686                }
 4687                // If the previous character is not a whitespace, we are in the middle of a word
 4688                // and we only want to complete the shortcode if the word is made up of other emojis
 4689                let mut containing_word = String::new();
 4690                for ch in snapshot
 4691                    .reversed_chars_at(position)
 4692                    .skip(chars.len() + 1)
 4693                    .take(100)
 4694                {
 4695                    if ch.is_whitespace() {
 4696                        break;
 4697                    }
 4698                    containing_word.push(ch);
 4699                }
 4700                let containing_word = containing_word.chars().rev().collect::<String>();
 4701                if util::word_consists_of_emojis(containing_word.as_str()) {
 4702                    chars.reverse();
 4703                    return Some(chars.iter().collect());
 4704                }
 4705            }
 4706
 4707            if char.is_whitespace() || !char.is_ascii() {
 4708                return None;
 4709            }
 4710            if char == ':' {
 4711                found_colon = true;
 4712            } else {
 4713                chars.push(char);
 4714            }
 4715        }
 4716        // Found a possible emoji shortcode at the beginning of the buffer
 4717        chars.reverse();
 4718        Some(chars.iter().collect())
 4719    }
 4720
 4721    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4722        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4723        self.transact(window, cx, |this, window, cx| {
 4724            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4725                let selections = this
 4726                    .selections
 4727                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4728                let multi_buffer = this.buffer.read(cx);
 4729                let buffer = multi_buffer.snapshot(cx);
 4730                selections
 4731                    .iter()
 4732                    .map(|selection| {
 4733                        let start_point = selection.start.to_point(&buffer);
 4734                        let mut existing_indent =
 4735                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4736                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4737                        let start = selection.start;
 4738                        let end = selection.end;
 4739                        let selection_is_empty = start == end;
 4740                        let language_scope = buffer.language_scope_at(start);
 4741                        let (
 4742                            comment_delimiter,
 4743                            doc_delimiter,
 4744                            insert_extra_newline,
 4745                            indent_on_newline,
 4746                            indent_on_extra_newline,
 4747                        ) = if let Some(language) = &language_scope {
 4748                            let mut insert_extra_newline =
 4749                                insert_extra_newline_brackets(&buffer, start..end, language)
 4750                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4751
 4752                            // Comment extension on newline is allowed only for cursor selections
 4753                            let comment_delimiter = maybe!({
 4754                                if !selection_is_empty {
 4755                                    return None;
 4756                                }
 4757
 4758                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4759                                    return None;
 4760                                }
 4761
 4762                                let delimiters = language.line_comment_prefixes();
 4763                                let max_len_of_delimiter =
 4764                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4765                                let (snapshot, range) =
 4766                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4767
 4768                                let num_of_whitespaces = snapshot
 4769                                    .chars_for_range(range.clone())
 4770                                    .take_while(|c| c.is_whitespace())
 4771                                    .count();
 4772                                let comment_candidate = snapshot
 4773                                    .chars_for_range(range.clone())
 4774                                    .skip(num_of_whitespaces)
 4775                                    .take(max_len_of_delimiter)
 4776                                    .collect::<String>();
 4777                                let (delimiter, trimmed_len) = delimiters
 4778                                    .iter()
 4779                                    .filter_map(|delimiter| {
 4780                                        let prefix = delimiter.trim_end();
 4781                                        if comment_candidate.starts_with(prefix) {
 4782                                            Some((delimiter, prefix.len()))
 4783                                        } else {
 4784                                            None
 4785                                        }
 4786                                    })
 4787                                    .max_by_key(|(_, len)| *len)?;
 4788
 4789                                if let Some(BlockCommentConfig {
 4790                                    start: block_start, ..
 4791                                }) = language.block_comment()
 4792                                {
 4793                                    let block_start_trimmed = block_start.trim_end();
 4794                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4795                                        let line_content = snapshot
 4796                                            .chars_for_range(range)
 4797                                            .skip(num_of_whitespaces)
 4798                                            .take(block_start_trimmed.len())
 4799                                            .collect::<String>();
 4800
 4801                                        if line_content.starts_with(block_start_trimmed) {
 4802                                            return None;
 4803                                        }
 4804                                    }
 4805                                }
 4806
 4807                                let cursor_is_placed_after_comment_marker =
 4808                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4809                                if cursor_is_placed_after_comment_marker {
 4810                                    Some(delimiter.clone())
 4811                                } else {
 4812                                    None
 4813                                }
 4814                            });
 4815
 4816                            let mut indent_on_newline = IndentSize::spaces(0);
 4817                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4818
 4819                            let doc_delimiter = maybe!({
 4820                                if !selection_is_empty {
 4821                                    return None;
 4822                                }
 4823
 4824                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4825                                    return None;
 4826                                }
 4827
 4828                                let BlockCommentConfig {
 4829                                    start: start_tag,
 4830                                    end: end_tag,
 4831                                    prefix: delimiter,
 4832                                    tab_size: len,
 4833                                } = language.documentation_comment()?;
 4834                                let is_within_block_comment = buffer
 4835                                    .language_scope_at(start_point)
 4836                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4837                                if !is_within_block_comment {
 4838                                    return None;
 4839                                }
 4840
 4841                                let (snapshot, range) =
 4842                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4843
 4844                                let num_of_whitespaces = snapshot
 4845                                    .chars_for_range(range.clone())
 4846                                    .take_while(|c| c.is_whitespace())
 4847                                    .count();
 4848
 4849                                // 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.
 4850                                let column = start_point.column;
 4851                                let cursor_is_after_start_tag = {
 4852                                    let start_tag_len = start_tag.len();
 4853                                    let start_tag_line = snapshot
 4854                                        .chars_for_range(range.clone())
 4855                                        .skip(num_of_whitespaces)
 4856                                        .take(start_tag_len)
 4857                                        .collect::<String>();
 4858                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4859                                        num_of_whitespaces + start_tag_len <= column as usize
 4860                                    } else {
 4861                                        false
 4862                                    }
 4863                                };
 4864
 4865                                let cursor_is_after_delimiter = {
 4866                                    let delimiter_trim = delimiter.trim_end();
 4867                                    let delimiter_line = snapshot
 4868                                        .chars_for_range(range.clone())
 4869                                        .skip(num_of_whitespaces)
 4870                                        .take(delimiter_trim.len())
 4871                                        .collect::<String>();
 4872                                    if delimiter_line.starts_with(delimiter_trim) {
 4873                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4874                                    } else {
 4875                                        false
 4876                                    }
 4877                                };
 4878
 4879                                let cursor_is_before_end_tag_if_exists = {
 4880                                    let mut char_position = 0u32;
 4881                                    let mut end_tag_offset = None;
 4882
 4883                                    'outer: for chunk in snapshot.text_for_range(range) {
 4884                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4885                                            let chars_before_match =
 4886                                                chunk[..byte_pos].chars().count() as u32;
 4887                                            end_tag_offset =
 4888                                                Some(char_position + chars_before_match);
 4889                                            break 'outer;
 4890                                        }
 4891                                        char_position += chunk.chars().count() as u32;
 4892                                    }
 4893
 4894                                    if let Some(end_tag_offset) = end_tag_offset {
 4895                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4896                                        if cursor_is_after_start_tag {
 4897                                            if cursor_is_before_end_tag {
 4898                                                insert_extra_newline = true;
 4899                                            }
 4900                                            let cursor_is_at_start_of_end_tag =
 4901                                                column == end_tag_offset;
 4902                                            if cursor_is_at_start_of_end_tag {
 4903                                                indent_on_extra_newline.len = *len;
 4904                                            }
 4905                                        }
 4906                                        cursor_is_before_end_tag
 4907                                    } else {
 4908                                        true
 4909                                    }
 4910                                };
 4911
 4912                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4913                                    && cursor_is_before_end_tag_if_exists
 4914                                {
 4915                                    if cursor_is_after_start_tag {
 4916                                        indent_on_newline.len = *len;
 4917                                    }
 4918                                    Some(delimiter.clone())
 4919                                } else {
 4920                                    None
 4921                                }
 4922                            });
 4923
 4924                            (
 4925                                comment_delimiter,
 4926                                doc_delimiter,
 4927                                insert_extra_newline,
 4928                                indent_on_newline,
 4929                                indent_on_extra_newline,
 4930                            )
 4931                        } else {
 4932                            (
 4933                                None,
 4934                                None,
 4935                                false,
 4936                                IndentSize::default(),
 4937                                IndentSize::default(),
 4938                            )
 4939                        };
 4940
 4941                        let prevent_auto_indent = doc_delimiter.is_some();
 4942                        let delimiter = comment_delimiter.or(doc_delimiter);
 4943
 4944                        let capacity_for_delimiter =
 4945                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4946                        let mut new_text = String::with_capacity(
 4947                            1 + capacity_for_delimiter
 4948                                + existing_indent.len as usize
 4949                                + indent_on_newline.len as usize
 4950                                + indent_on_extra_newline.len as usize,
 4951                        );
 4952                        new_text.push('\n');
 4953                        new_text.extend(existing_indent.chars());
 4954                        new_text.extend(indent_on_newline.chars());
 4955
 4956                        if let Some(delimiter) = &delimiter {
 4957                            new_text.push_str(delimiter);
 4958                        }
 4959
 4960                        if insert_extra_newline {
 4961                            new_text.push('\n');
 4962                            new_text.extend(existing_indent.chars());
 4963                            new_text.extend(indent_on_extra_newline.chars());
 4964                        }
 4965
 4966                        let anchor = buffer.anchor_after(end);
 4967                        let new_selection = selection.map(|_| anchor);
 4968                        (
 4969                            ((start..end, new_text), prevent_auto_indent),
 4970                            (insert_extra_newline, new_selection),
 4971                        )
 4972                    })
 4973                    .unzip()
 4974            };
 4975
 4976            let mut auto_indent_edits = Vec::new();
 4977            let mut edits = Vec::new();
 4978            for (edit, prevent_auto_indent) in edits_with_flags {
 4979                if prevent_auto_indent {
 4980                    edits.push(edit);
 4981                } else {
 4982                    auto_indent_edits.push(edit);
 4983                }
 4984            }
 4985            if !edits.is_empty() {
 4986                this.edit(edits, cx);
 4987            }
 4988            if !auto_indent_edits.is_empty() {
 4989                this.edit_with_autoindent(auto_indent_edits, cx);
 4990            }
 4991
 4992            let buffer = this.buffer.read(cx).snapshot(cx);
 4993            let new_selections = selection_info
 4994                .into_iter()
 4995                .map(|(extra_newline_inserted, new_selection)| {
 4996                    let mut cursor = new_selection.end.to_point(&buffer);
 4997                    if extra_newline_inserted {
 4998                        cursor.row -= 1;
 4999                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5000                    }
 5001                    new_selection.map(|_| cursor)
 5002                })
 5003                .collect();
 5004
 5005            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5006            this.refresh_edit_prediction(true, false, window, cx);
 5007        });
 5008    }
 5009
 5010    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5011        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5012
 5013        let buffer = self.buffer.read(cx);
 5014        let snapshot = buffer.snapshot(cx);
 5015
 5016        let mut edits = Vec::new();
 5017        let mut rows = Vec::new();
 5018
 5019        for (rows_inserted, selection) in self
 5020            .selections
 5021            .all_adjusted(&self.display_snapshot(cx))
 5022            .into_iter()
 5023            .enumerate()
 5024        {
 5025            let cursor = selection.head();
 5026            let row = cursor.row;
 5027
 5028            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5029
 5030            let newline = "\n".to_string();
 5031            edits.push((start_of_line..start_of_line, newline));
 5032
 5033            rows.push(row + rows_inserted as u32);
 5034        }
 5035
 5036        self.transact(window, cx, |editor, window, cx| {
 5037            editor.edit(edits, cx);
 5038
 5039            editor.change_selections(Default::default(), window, cx, |s| {
 5040                let mut index = 0;
 5041                s.move_cursors_with(|map, _, _| {
 5042                    let row = rows[index];
 5043                    index += 1;
 5044
 5045                    let point = Point::new(row, 0);
 5046                    let boundary = map.next_line_boundary(point).1;
 5047                    let clipped = map.clip_point(boundary, Bias::Left);
 5048
 5049                    (clipped, SelectionGoal::None)
 5050                });
 5051            });
 5052
 5053            let mut indent_edits = Vec::new();
 5054            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5055            for row in rows {
 5056                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5057                for (row, indent) in indents {
 5058                    if indent.len == 0 {
 5059                        continue;
 5060                    }
 5061
 5062                    let text = match indent.kind {
 5063                        IndentKind::Space => " ".repeat(indent.len as usize),
 5064                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5065                    };
 5066                    let point = Point::new(row.0, 0);
 5067                    indent_edits.push((point..point, text));
 5068                }
 5069            }
 5070            editor.edit(indent_edits, cx);
 5071        });
 5072    }
 5073
 5074    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5075        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5076
 5077        let buffer = self.buffer.read(cx);
 5078        let snapshot = buffer.snapshot(cx);
 5079
 5080        let mut edits = Vec::new();
 5081        let mut rows = Vec::new();
 5082        let mut rows_inserted = 0;
 5083
 5084        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5085            let cursor = selection.head();
 5086            let row = cursor.row;
 5087
 5088            let point = Point::new(row + 1, 0);
 5089            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5090
 5091            let newline = "\n".to_string();
 5092            edits.push((start_of_line..start_of_line, newline));
 5093
 5094            rows_inserted += 1;
 5095            rows.push(row + rows_inserted);
 5096        }
 5097
 5098        self.transact(window, cx, |editor, window, cx| {
 5099            editor.edit(edits, cx);
 5100
 5101            editor.change_selections(Default::default(), window, cx, |s| {
 5102                let mut index = 0;
 5103                s.move_cursors_with(|map, _, _| {
 5104                    let row = rows[index];
 5105                    index += 1;
 5106
 5107                    let point = Point::new(row, 0);
 5108                    let boundary = map.next_line_boundary(point).1;
 5109                    let clipped = map.clip_point(boundary, Bias::Left);
 5110
 5111                    (clipped, SelectionGoal::None)
 5112                });
 5113            });
 5114
 5115            let mut indent_edits = Vec::new();
 5116            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5117            for row in rows {
 5118                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5119                for (row, indent) in indents {
 5120                    if indent.len == 0 {
 5121                        continue;
 5122                    }
 5123
 5124                    let text = match indent.kind {
 5125                        IndentKind::Space => " ".repeat(indent.len as usize),
 5126                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5127                    };
 5128                    let point = Point::new(row.0, 0);
 5129                    indent_edits.push((point..point, text));
 5130                }
 5131            }
 5132            editor.edit(indent_edits, cx);
 5133        });
 5134    }
 5135
 5136    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5137        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5138            original_indent_columns: Vec::new(),
 5139        });
 5140        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5141    }
 5142
 5143    fn insert_with_autoindent_mode(
 5144        &mut self,
 5145        text: &str,
 5146        autoindent_mode: Option<AutoindentMode>,
 5147        window: &mut Window,
 5148        cx: &mut Context<Self>,
 5149    ) {
 5150        if self.read_only(cx) {
 5151            return;
 5152        }
 5153
 5154        let text: Arc<str> = text.into();
 5155        self.transact(window, cx, |this, window, cx| {
 5156            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5157            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5158                let anchors = {
 5159                    let snapshot = buffer.read(cx);
 5160                    old_selections
 5161                        .iter()
 5162                        .map(|s| {
 5163                            let anchor = snapshot.anchor_after(s.head());
 5164                            s.map(|_| anchor)
 5165                        })
 5166                        .collect::<Vec<_>>()
 5167                };
 5168                buffer.edit(
 5169                    old_selections
 5170                        .iter()
 5171                        .map(|s| (s.start..s.end, text.clone())),
 5172                    autoindent_mode,
 5173                    cx,
 5174                );
 5175                anchors
 5176            });
 5177
 5178            this.change_selections(Default::default(), window, cx, |s| {
 5179                s.select_anchors(selection_anchors);
 5180            });
 5181
 5182            cx.notify();
 5183        });
 5184    }
 5185
 5186    fn trigger_completion_on_input(
 5187        &mut self,
 5188        text: &str,
 5189        trigger_in_words: bool,
 5190        window: &mut Window,
 5191        cx: &mut Context<Self>,
 5192    ) {
 5193        let completions_source = self
 5194            .context_menu
 5195            .borrow()
 5196            .as_ref()
 5197            .and_then(|menu| match menu {
 5198                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5199                CodeContextMenu::CodeActions(_) => None,
 5200            });
 5201
 5202        match completions_source {
 5203            Some(CompletionsMenuSource::Words { .. }) => {
 5204                self.open_or_update_completions_menu(
 5205                    Some(CompletionsMenuSource::Words {
 5206                        ignore_threshold: false,
 5207                    }),
 5208                    None,
 5209                    trigger_in_words,
 5210                    window,
 5211                    cx,
 5212                );
 5213            }
 5214            _ => self.open_or_update_completions_menu(
 5215                None,
 5216                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5217                true,
 5218                window,
 5219                cx,
 5220            ),
 5221        }
 5222    }
 5223
 5224    /// If any empty selections is touching the start of its innermost containing autoclose
 5225    /// region, expand it to select the brackets.
 5226    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5227        let selections = self
 5228            .selections
 5229            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5230        let buffer = self.buffer.read(cx).read(cx);
 5231        let new_selections = self
 5232            .selections_with_autoclose_regions(selections, &buffer)
 5233            .map(|(mut selection, region)| {
 5234                if !selection.is_empty() {
 5235                    return selection;
 5236                }
 5237
 5238                if let Some(region) = region {
 5239                    let mut range = region.range.to_offset(&buffer);
 5240                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5241                        range.start -= region.pair.start.len();
 5242                        if buffer.contains_str_at(range.start, &region.pair.start)
 5243                            && buffer.contains_str_at(range.end, &region.pair.end)
 5244                        {
 5245                            range.end += region.pair.end.len();
 5246                            selection.start = range.start;
 5247                            selection.end = range.end;
 5248
 5249                            return selection;
 5250                        }
 5251                    }
 5252                }
 5253
 5254                let always_treat_brackets_as_autoclosed = buffer
 5255                    .language_settings_at(selection.start, cx)
 5256                    .always_treat_brackets_as_autoclosed;
 5257
 5258                if !always_treat_brackets_as_autoclosed {
 5259                    return selection;
 5260                }
 5261
 5262                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5263                    for (pair, enabled) in scope.brackets() {
 5264                        if !enabled || !pair.close {
 5265                            continue;
 5266                        }
 5267
 5268                        if buffer.contains_str_at(selection.start, &pair.end) {
 5269                            let pair_start_len = pair.start.len();
 5270                            if buffer.contains_str_at(
 5271                                selection.start.saturating_sub_usize(pair_start_len),
 5272                                &pair.start,
 5273                            ) {
 5274                                selection.start -= pair_start_len;
 5275                                selection.end += pair.end.len();
 5276
 5277                                return selection;
 5278                            }
 5279                        }
 5280                    }
 5281                }
 5282
 5283                selection
 5284            })
 5285            .collect();
 5286
 5287        drop(buffer);
 5288        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5289            selections.select(new_selections)
 5290        });
 5291    }
 5292
 5293    /// Iterate the given selections, and for each one, find the smallest surrounding
 5294    /// autoclose region. This uses the ordering of the selections and the autoclose
 5295    /// regions to avoid repeated comparisons.
 5296    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5297        &'a self,
 5298        selections: impl IntoIterator<Item = Selection<D>>,
 5299        buffer: &'a MultiBufferSnapshot,
 5300    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5301        let mut i = 0;
 5302        let mut regions = self.autoclose_regions.as_slice();
 5303        selections.into_iter().map(move |selection| {
 5304            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5305
 5306            let mut enclosing = None;
 5307            while let Some(pair_state) = regions.get(i) {
 5308                if pair_state.range.end.to_offset(buffer) < range.start {
 5309                    regions = &regions[i + 1..];
 5310                    i = 0;
 5311                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5312                    break;
 5313                } else {
 5314                    if pair_state.selection_id == selection.id {
 5315                        enclosing = Some(pair_state);
 5316                    }
 5317                    i += 1;
 5318                }
 5319            }
 5320
 5321            (selection, enclosing)
 5322        })
 5323    }
 5324
 5325    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5326    fn invalidate_autoclose_regions(
 5327        &mut self,
 5328        mut selections: &[Selection<Anchor>],
 5329        buffer: &MultiBufferSnapshot,
 5330    ) {
 5331        self.autoclose_regions.retain(|state| {
 5332            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5333                return false;
 5334            }
 5335
 5336            let mut i = 0;
 5337            while let Some(selection) = selections.get(i) {
 5338                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5339                    selections = &selections[1..];
 5340                    continue;
 5341                }
 5342                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5343                    break;
 5344                }
 5345                if selection.id == state.selection_id {
 5346                    return true;
 5347                } else {
 5348                    i += 1;
 5349                }
 5350            }
 5351            false
 5352        });
 5353    }
 5354
 5355    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5356        let offset = position.to_offset(buffer);
 5357        let (word_range, kind) =
 5358            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5359        if offset > word_range.start && kind == Some(CharKind::Word) {
 5360            Some(
 5361                buffer
 5362                    .text_for_range(word_range.start..offset)
 5363                    .collect::<String>(),
 5364            )
 5365        } else {
 5366            None
 5367        }
 5368    }
 5369
 5370    pub fn visible_excerpts(
 5371        &self,
 5372        lsp_related_only: bool,
 5373        cx: &mut Context<Editor>,
 5374    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5375        let project = self.project().cloned();
 5376        let multi_buffer = self.buffer().read(cx);
 5377        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5378        let multi_buffer_visible_start = self
 5379            .scroll_manager
 5380            .anchor()
 5381            .anchor
 5382            .to_point(&multi_buffer_snapshot);
 5383        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5384            multi_buffer_visible_start
 5385                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5386            Bias::Left,
 5387        );
 5388        multi_buffer_snapshot
 5389            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5390            .into_iter()
 5391            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5392            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5393                if !lsp_related_only {
 5394                    return Some((
 5395                        excerpt_id,
 5396                        (
 5397                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5398                            buffer.version().clone(),
 5399                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5400                        ),
 5401                    ));
 5402                }
 5403
 5404                let project = project.as_ref()?.read(cx);
 5405                let buffer_file = project::File::from_dyn(buffer.file())?;
 5406                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5407                let worktree_entry = buffer_worktree
 5408                    .read(cx)
 5409                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5410                if worktree_entry.is_ignored {
 5411                    None
 5412                } else {
 5413                    Some((
 5414                        excerpt_id,
 5415                        (
 5416                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5417                            buffer.version().clone(),
 5418                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5419                        ),
 5420                    ))
 5421                }
 5422            })
 5423            .collect()
 5424    }
 5425
 5426    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5427        TextLayoutDetails {
 5428            text_system: window.text_system().clone(),
 5429            editor_style: self.style.clone().unwrap(),
 5430            rem_size: window.rem_size(),
 5431            scroll_anchor: self.scroll_manager.anchor(),
 5432            visible_rows: self.visible_line_count(),
 5433            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5434        }
 5435    }
 5436
 5437    fn trigger_on_type_formatting(
 5438        &self,
 5439        input: String,
 5440        window: &mut Window,
 5441        cx: &mut Context<Self>,
 5442    ) -> Option<Task<Result<()>>> {
 5443        if input.len() != 1 {
 5444            return None;
 5445        }
 5446
 5447        let project = self.project()?;
 5448        let position = self.selections.newest_anchor().head();
 5449        let (buffer, buffer_position) = self
 5450            .buffer
 5451            .read(cx)
 5452            .text_anchor_for_position(position, cx)?;
 5453
 5454        let settings = language_settings::language_settings(
 5455            buffer
 5456                .read(cx)
 5457                .language_at(buffer_position)
 5458                .map(|l| l.name()),
 5459            buffer.read(cx).file(),
 5460            cx,
 5461        );
 5462        if !settings.use_on_type_format {
 5463            return None;
 5464        }
 5465
 5466        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5467        // hence we do LSP request & edit on host side only — add formats to host's history.
 5468        let push_to_lsp_host_history = true;
 5469        // If this is not the host, append its history with new edits.
 5470        let push_to_client_history = project.read(cx).is_via_collab();
 5471
 5472        let on_type_formatting = project.update(cx, |project, cx| {
 5473            project.on_type_format(
 5474                buffer.clone(),
 5475                buffer_position,
 5476                input,
 5477                push_to_lsp_host_history,
 5478                cx,
 5479            )
 5480        });
 5481        Some(cx.spawn_in(window, async move |editor, cx| {
 5482            if let Some(transaction) = on_type_formatting.await? {
 5483                if push_to_client_history {
 5484                    buffer
 5485                        .update(cx, |buffer, _| {
 5486                            buffer.push_transaction(transaction, Instant::now());
 5487                            buffer.finalize_last_transaction();
 5488                        })
 5489                        .ok();
 5490                }
 5491                editor.update(cx, |editor, cx| {
 5492                    editor.refresh_document_highlights(cx);
 5493                })?;
 5494            }
 5495            Ok(())
 5496        }))
 5497    }
 5498
 5499    pub fn show_word_completions(
 5500        &mut self,
 5501        _: &ShowWordCompletions,
 5502        window: &mut Window,
 5503        cx: &mut Context<Self>,
 5504    ) {
 5505        self.open_or_update_completions_menu(
 5506            Some(CompletionsMenuSource::Words {
 5507                ignore_threshold: true,
 5508            }),
 5509            None,
 5510            false,
 5511            window,
 5512            cx,
 5513        );
 5514    }
 5515
 5516    pub fn show_completions(
 5517        &mut self,
 5518        _: &ShowCompletions,
 5519        window: &mut Window,
 5520        cx: &mut Context<Self>,
 5521    ) {
 5522        self.open_or_update_completions_menu(None, None, false, window, cx);
 5523    }
 5524
 5525    fn open_or_update_completions_menu(
 5526        &mut self,
 5527        requested_source: Option<CompletionsMenuSource>,
 5528        trigger: Option<String>,
 5529        trigger_in_words: bool,
 5530        window: &mut Window,
 5531        cx: &mut Context<Self>,
 5532    ) {
 5533        if self.pending_rename.is_some() {
 5534            return;
 5535        }
 5536
 5537        let completions_source = self
 5538            .context_menu
 5539            .borrow()
 5540            .as_ref()
 5541            .and_then(|menu| match menu {
 5542                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5543                CodeContextMenu::CodeActions(_) => None,
 5544            });
 5545
 5546        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5547
 5548        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5549        // inserted and selected. To handle that case, the start of the selection is used so that
 5550        // the menu starts with all choices.
 5551        let position = self
 5552            .selections
 5553            .newest_anchor()
 5554            .start
 5555            .bias_right(&multibuffer_snapshot);
 5556        if position.diff_base_anchor.is_some() {
 5557            return;
 5558        }
 5559        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5560        let Some(buffer) = buffer_position
 5561            .text_anchor
 5562            .buffer_id
 5563            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5564        else {
 5565            return;
 5566        };
 5567        let buffer_snapshot = buffer.read(cx).snapshot();
 5568
 5569        let menu_is_open = matches!(
 5570            self.context_menu.borrow().as_ref(),
 5571            Some(CodeContextMenu::Completions(_))
 5572        );
 5573
 5574        let language = buffer_snapshot
 5575            .language_at(buffer_position.text_anchor)
 5576            .map(|language| language.name());
 5577
 5578        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5579        let completion_settings = language_settings.completions.clone();
 5580
 5581        let show_completions_on_input = self
 5582            .show_completions_on_input_override
 5583            .unwrap_or(language_settings.show_completions_on_input);
 5584        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5585            return;
 5586        }
 5587
 5588        let query: Option<Arc<String>> =
 5589            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5590                .map(|query| query.into());
 5591
 5592        drop(multibuffer_snapshot);
 5593
 5594        // Hide the current completions menu when query is empty. Without this, cached
 5595        // completions from before the trigger char may be reused (#32774).
 5596        if query.is_none() && menu_is_open {
 5597            self.hide_context_menu(window, cx);
 5598        }
 5599
 5600        let mut ignore_word_threshold = false;
 5601        let provider = match requested_source {
 5602            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5603            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5604                ignore_word_threshold = ignore_threshold;
 5605                None
 5606            }
 5607            Some(CompletionsMenuSource::SnippetChoices)
 5608            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5609                log::error!("bug: SnippetChoices requested_source is not handled");
 5610                None
 5611            }
 5612        };
 5613
 5614        let sort_completions = provider
 5615            .as_ref()
 5616            .is_some_and(|provider| provider.sort_completions());
 5617
 5618        let filter_completions = provider
 5619            .as_ref()
 5620            .is_none_or(|provider| provider.filter_completions());
 5621
 5622        let was_snippets_only = matches!(
 5623            completions_source,
 5624            Some(CompletionsMenuSource::SnippetsOnly)
 5625        );
 5626
 5627        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5628            if filter_completions {
 5629                menu.filter(
 5630                    query.clone().unwrap_or_default(),
 5631                    buffer_position.text_anchor,
 5632                    &buffer,
 5633                    provider.clone(),
 5634                    window,
 5635                    cx,
 5636                );
 5637            }
 5638            // When `is_incomplete` is false, no need to re-query completions when the current query
 5639            // is a suffix of the initial query.
 5640            let was_complete = !menu.is_incomplete;
 5641            if was_complete && !was_snippets_only {
 5642                // If the new query is a suffix of the old query (typing more characters) and
 5643                // the previous result was complete, the existing completions can be filtered.
 5644                //
 5645                // Note that snippet completions are always complete.
 5646                let query_matches = match (&menu.initial_query, &query) {
 5647                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5648                    (None, _) => true,
 5649                    _ => false,
 5650                };
 5651                if query_matches {
 5652                    let position_matches = if menu.initial_position == position {
 5653                        true
 5654                    } else {
 5655                        let snapshot = self.buffer.read(cx).read(cx);
 5656                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5657                    };
 5658                    if position_matches {
 5659                        return;
 5660                    }
 5661                }
 5662            }
 5663        };
 5664
 5665        let Anchor {
 5666            excerpt_id: buffer_excerpt_id,
 5667            text_anchor: buffer_position,
 5668            ..
 5669        } = buffer_position;
 5670
 5671        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5672            buffer_snapshot.surrounding_word(buffer_position, None)
 5673        {
 5674            let word_to_exclude = buffer_snapshot
 5675                .text_for_range(word_range.clone())
 5676                .collect::<String>();
 5677            (
 5678                buffer_snapshot.anchor_before(word_range.start)
 5679                    ..buffer_snapshot.anchor_after(buffer_position),
 5680                Some(word_to_exclude),
 5681            )
 5682        } else {
 5683            (buffer_position..buffer_position, None)
 5684        };
 5685
 5686        let show_completion_documentation = buffer_snapshot
 5687            .settings_at(buffer_position, cx)
 5688            .show_completion_documentation;
 5689
 5690        // The document can be large, so stay in reasonable bounds when searching for words,
 5691        // otherwise completion pop-up might be slow to appear.
 5692        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5693        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5694        let min_word_search = buffer_snapshot.clip_point(
 5695            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5696            Bias::Left,
 5697        );
 5698        let max_word_search = buffer_snapshot.clip_point(
 5699            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5700            Bias::Right,
 5701        );
 5702        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5703            ..buffer_snapshot.point_to_offset(max_word_search);
 5704
 5705        let skip_digits = query
 5706            .as_ref()
 5707            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5708
 5709        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5710            trigger.as_ref().is_none_or(|trigger| {
 5711                provider.is_completion_trigger(
 5712                    &buffer,
 5713                    position.text_anchor,
 5714                    trigger,
 5715                    trigger_in_words,
 5716                    cx,
 5717                )
 5718            })
 5719        });
 5720
 5721        let provider_responses = if let Some(provider) = &provider
 5722            && load_provider_completions
 5723        {
 5724            let trigger_character =
 5725                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5726            let completion_context = CompletionContext {
 5727                trigger_kind: match &trigger_character {
 5728                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5729                    None => CompletionTriggerKind::INVOKED,
 5730                },
 5731                trigger_character,
 5732            };
 5733
 5734            provider.completions(
 5735                buffer_excerpt_id,
 5736                &buffer,
 5737                buffer_position,
 5738                completion_context,
 5739                window,
 5740                cx,
 5741            )
 5742        } else {
 5743            Task::ready(Ok(Vec::new()))
 5744        };
 5745
 5746        let load_word_completions = if !self.word_completions_enabled {
 5747            false
 5748        } else if requested_source
 5749            == Some(CompletionsMenuSource::Words {
 5750                ignore_threshold: true,
 5751            })
 5752        {
 5753            true
 5754        } else {
 5755            load_provider_completions
 5756                && completion_settings.words != WordsCompletionMode::Disabled
 5757                && (ignore_word_threshold || {
 5758                    let words_min_length = completion_settings.words_min_length;
 5759                    // check whether word has at least `words_min_length` characters
 5760                    let query_chars = query.iter().flat_map(|q| q.chars());
 5761                    query_chars.take(words_min_length).count() == words_min_length
 5762                })
 5763        };
 5764
 5765        let mut words = if load_word_completions {
 5766            cx.background_spawn({
 5767                let buffer_snapshot = buffer_snapshot.clone();
 5768                async move {
 5769                    buffer_snapshot.words_in_range(WordsQuery {
 5770                        fuzzy_contents: None,
 5771                        range: word_search_range,
 5772                        skip_digits,
 5773                    })
 5774                }
 5775            })
 5776        } else {
 5777            Task::ready(BTreeMap::default())
 5778        };
 5779
 5780        let snippets = if let Some(provider) = &provider
 5781            && provider.show_snippets()
 5782            && let Some(project) = self.project()
 5783        {
 5784            let char_classifier = buffer_snapshot
 5785                .char_classifier_at(buffer_position)
 5786                .scope_context(Some(CharScopeContext::Completion));
 5787            project.update(cx, |project, cx| {
 5788                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5789            })
 5790        } else {
 5791            Task::ready(Ok(CompletionResponse {
 5792                completions: Vec::new(),
 5793                display_options: Default::default(),
 5794                is_incomplete: false,
 5795            }))
 5796        };
 5797
 5798        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5799
 5800        let id = post_inc(&mut self.next_completion_id);
 5801        let task = cx.spawn_in(window, async move |editor, cx| {
 5802            let Ok(()) = editor.update(cx, |this, _| {
 5803                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5804            }) else {
 5805                return;
 5806            };
 5807
 5808            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5809            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5810            let mut completions = Vec::new();
 5811            let mut is_incomplete = false;
 5812            let mut display_options: Option<CompletionDisplayOptions> = None;
 5813            if let Some(provider_responses) = provider_responses.await.log_err()
 5814                && !provider_responses.is_empty()
 5815            {
 5816                for response in provider_responses {
 5817                    completions.extend(response.completions);
 5818                    is_incomplete = is_incomplete || response.is_incomplete;
 5819                    match display_options.as_mut() {
 5820                        None => {
 5821                            display_options = Some(response.display_options);
 5822                        }
 5823                        Some(options) => options.merge(&response.display_options),
 5824                    }
 5825                }
 5826                if completion_settings.words == WordsCompletionMode::Fallback {
 5827                    words = Task::ready(BTreeMap::default());
 5828                }
 5829            }
 5830            let display_options = display_options.unwrap_or_default();
 5831
 5832            let mut words = words.await;
 5833            if let Some(word_to_exclude) = &word_to_exclude {
 5834                words.remove(word_to_exclude);
 5835            }
 5836            for lsp_completion in &completions {
 5837                words.remove(&lsp_completion.new_text);
 5838            }
 5839            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5840                replace_range: word_replace_range.clone(),
 5841                new_text: word.clone(),
 5842                label: CodeLabel::plain(word, None),
 5843                match_start: None,
 5844                snippet_deduplication_key: None,
 5845                icon_path: None,
 5846                documentation: None,
 5847                source: CompletionSource::BufferWord {
 5848                    word_range,
 5849                    resolved: false,
 5850                },
 5851                insert_text_mode: Some(InsertTextMode::AS_IS),
 5852                confirm: None,
 5853            }));
 5854
 5855            completions.extend(
 5856                snippets
 5857                    .await
 5858                    .into_iter()
 5859                    .flat_map(|response| response.completions),
 5860            );
 5861
 5862            let menu = if completions.is_empty() {
 5863                None
 5864            } else {
 5865                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5866                    let languages = editor
 5867                        .workspace
 5868                        .as_ref()
 5869                        .and_then(|(workspace, _)| workspace.upgrade())
 5870                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5871                    let menu = CompletionsMenu::new(
 5872                        id,
 5873                        requested_source.unwrap_or(if load_provider_completions {
 5874                            CompletionsMenuSource::Normal
 5875                        } else {
 5876                            CompletionsMenuSource::SnippetsOnly
 5877                        }),
 5878                        sort_completions,
 5879                        show_completion_documentation,
 5880                        position,
 5881                        query.clone(),
 5882                        is_incomplete,
 5883                        buffer.clone(),
 5884                        completions.into(),
 5885                        display_options,
 5886                        snippet_sort_order,
 5887                        languages,
 5888                        language,
 5889                        cx,
 5890                    );
 5891
 5892                    let query = if filter_completions { query } else { None };
 5893                    let matches_task = menu.do_async_filtering(
 5894                        query.unwrap_or_default(),
 5895                        buffer_position,
 5896                        &buffer,
 5897                        cx,
 5898                    );
 5899                    (menu, matches_task)
 5900                }) else {
 5901                    return;
 5902                };
 5903
 5904                let matches = matches_task.await;
 5905
 5906                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5907                    // Newer menu already set, so exit.
 5908                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5909                        editor.context_menu.borrow().as_ref()
 5910                        && prev_menu.id > id
 5911                    {
 5912                        return;
 5913                    };
 5914
 5915                    // Only valid to take prev_menu because either the new menu is immediately set
 5916                    // below, or the menu is hidden.
 5917                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5918                        editor.context_menu.borrow_mut().take()
 5919                    {
 5920                        let position_matches =
 5921                            if prev_menu.initial_position == menu.initial_position {
 5922                                true
 5923                            } else {
 5924                                let snapshot = editor.buffer.read(cx).read(cx);
 5925                                prev_menu.initial_position.to_offset(&snapshot)
 5926                                    == menu.initial_position.to_offset(&snapshot)
 5927                            };
 5928                        if position_matches {
 5929                            // Preserve markdown cache before `set_filter_results` because it will
 5930                            // try to populate the documentation cache.
 5931                            menu.preserve_markdown_cache(prev_menu);
 5932                        }
 5933                    };
 5934
 5935                    menu.set_filter_results(matches, provider, window, cx);
 5936                }) else {
 5937                    return;
 5938                };
 5939
 5940                menu.visible().then_some(menu)
 5941            };
 5942
 5943            editor
 5944                .update_in(cx, |editor, window, cx| {
 5945                    if editor.focus_handle.is_focused(window)
 5946                        && let Some(menu) = menu
 5947                    {
 5948                        *editor.context_menu.borrow_mut() =
 5949                            Some(CodeContextMenu::Completions(menu));
 5950
 5951                        crate::hover_popover::hide_hover(editor, cx);
 5952                        if editor.show_edit_predictions_in_menu() {
 5953                            editor.update_visible_edit_prediction(window, cx);
 5954                        } else {
 5955                            editor.discard_edit_prediction(false, cx);
 5956                        }
 5957
 5958                        cx.notify();
 5959                        return;
 5960                    }
 5961
 5962                    if editor.completion_tasks.len() <= 1 {
 5963                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5964                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5965                        // If it was already hidden and we don't show edit predictions in the menu,
 5966                        // we should also show the edit prediction when available.
 5967                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5968                            editor.update_visible_edit_prediction(window, cx);
 5969                        }
 5970                    }
 5971                })
 5972                .ok();
 5973        });
 5974
 5975        self.completion_tasks.push((id, task));
 5976    }
 5977
 5978    #[cfg(feature = "test-support")]
 5979    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5980        let menu = self.context_menu.borrow();
 5981        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5982            let completions = menu.completions.borrow();
 5983            Some(completions.to_vec())
 5984        } else {
 5985            None
 5986        }
 5987    }
 5988
 5989    pub fn with_completions_menu_matching_id<R>(
 5990        &self,
 5991        id: CompletionId,
 5992        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5993    ) -> R {
 5994        let mut context_menu = self.context_menu.borrow_mut();
 5995        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5996            return f(None);
 5997        };
 5998        if completions_menu.id != id {
 5999            return f(None);
 6000        }
 6001        f(Some(completions_menu))
 6002    }
 6003
 6004    pub fn confirm_completion(
 6005        &mut self,
 6006        action: &ConfirmCompletion,
 6007        window: &mut Window,
 6008        cx: &mut Context<Self>,
 6009    ) -> Option<Task<Result<()>>> {
 6010        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6011        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6012    }
 6013
 6014    pub fn confirm_completion_insert(
 6015        &mut self,
 6016        _: &ConfirmCompletionInsert,
 6017        window: &mut Window,
 6018        cx: &mut Context<Self>,
 6019    ) -> Option<Task<Result<()>>> {
 6020        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6021        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6022    }
 6023
 6024    pub fn confirm_completion_replace(
 6025        &mut self,
 6026        _: &ConfirmCompletionReplace,
 6027        window: &mut Window,
 6028        cx: &mut Context<Self>,
 6029    ) -> Option<Task<Result<()>>> {
 6030        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6031        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6032    }
 6033
 6034    pub fn compose_completion(
 6035        &mut self,
 6036        action: &ComposeCompletion,
 6037        window: &mut Window,
 6038        cx: &mut Context<Self>,
 6039    ) -> Option<Task<Result<()>>> {
 6040        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6041        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6042    }
 6043
 6044    fn do_completion(
 6045        &mut self,
 6046        item_ix: Option<usize>,
 6047        intent: CompletionIntent,
 6048        window: &mut Window,
 6049        cx: &mut Context<Editor>,
 6050    ) -> Option<Task<Result<()>>> {
 6051        use language::ToOffset as _;
 6052
 6053        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6054        else {
 6055            return None;
 6056        };
 6057
 6058        let candidate_id = {
 6059            let entries = completions_menu.entries.borrow();
 6060            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6061            if self.show_edit_predictions_in_menu() {
 6062                self.discard_edit_prediction(true, cx);
 6063            }
 6064            mat.candidate_id
 6065        };
 6066
 6067        let completion = completions_menu
 6068            .completions
 6069            .borrow()
 6070            .get(candidate_id)?
 6071            .clone();
 6072        cx.stop_propagation();
 6073
 6074        let buffer_handle = completions_menu.buffer.clone();
 6075
 6076        let CompletionEdit {
 6077            new_text,
 6078            snippet,
 6079            replace_range,
 6080        } = process_completion_for_edit(
 6081            &completion,
 6082            intent,
 6083            &buffer_handle,
 6084            &completions_menu.initial_position.text_anchor,
 6085            cx,
 6086        );
 6087
 6088        let buffer = buffer_handle.read(cx);
 6089        let snapshot = self.buffer.read(cx).snapshot(cx);
 6090        let newest_anchor = self.selections.newest_anchor();
 6091        let replace_range_multibuffer = {
 6092            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6093            excerpt.map_range_from_buffer(replace_range.clone())
 6094        };
 6095        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6096            return None;
 6097        }
 6098
 6099        let old_text = buffer
 6100            .text_for_range(replace_range.clone())
 6101            .collect::<String>();
 6102        let lookbehind = newest_anchor
 6103            .start
 6104            .text_anchor
 6105            .to_offset(buffer)
 6106            .saturating_sub(replace_range.start.0);
 6107        let lookahead = replace_range
 6108            .end
 6109            .0
 6110            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6111        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6112        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6113
 6114        let selections = self
 6115            .selections
 6116            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6117        let mut ranges = Vec::new();
 6118        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6119
 6120        for selection in &selections {
 6121            let range = if selection.id == newest_anchor.id {
 6122                replace_range_multibuffer.clone()
 6123            } else {
 6124                let mut range = selection.range();
 6125
 6126                // if prefix is present, don't duplicate it
 6127                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6128                    range.start = range.start.saturating_sub_usize(lookbehind);
 6129
 6130                    // if suffix is also present, mimic the newest cursor and replace it
 6131                    if selection.id != newest_anchor.id
 6132                        && snapshot.contains_str_at(range.end, suffix)
 6133                    {
 6134                        range.end += lookahead;
 6135                    }
 6136                }
 6137                range
 6138            };
 6139
 6140            ranges.push(range.clone());
 6141
 6142            if !self.linked_edit_ranges.is_empty() {
 6143                let start_anchor = snapshot.anchor_before(range.start);
 6144                let end_anchor = snapshot.anchor_after(range.end);
 6145                if let Some(ranges) = self
 6146                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6147                {
 6148                    for (buffer, edits) in ranges {
 6149                        linked_edits
 6150                            .entry(buffer.clone())
 6151                            .or_default()
 6152                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6153                    }
 6154                }
 6155            }
 6156        }
 6157
 6158        let common_prefix_len = old_text
 6159            .chars()
 6160            .zip(new_text.chars())
 6161            .take_while(|(a, b)| a == b)
 6162            .map(|(a, _)| a.len_utf8())
 6163            .sum::<usize>();
 6164
 6165        cx.emit(EditorEvent::InputHandled {
 6166            utf16_range_to_replace: None,
 6167            text: new_text[common_prefix_len..].into(),
 6168        });
 6169
 6170        self.transact(window, cx, |editor, window, cx| {
 6171            if let Some(mut snippet) = snippet {
 6172                snippet.text = new_text.to_string();
 6173                editor
 6174                    .insert_snippet(&ranges, snippet, window, cx)
 6175                    .log_err();
 6176            } else {
 6177                editor.buffer.update(cx, |multi_buffer, cx| {
 6178                    let auto_indent = match completion.insert_text_mode {
 6179                        Some(InsertTextMode::AS_IS) => None,
 6180                        _ => editor.autoindent_mode.clone(),
 6181                    };
 6182                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6183                    multi_buffer.edit(edits, auto_indent, cx);
 6184                });
 6185            }
 6186            for (buffer, edits) in linked_edits {
 6187                buffer.update(cx, |buffer, cx| {
 6188                    let snapshot = buffer.snapshot();
 6189                    let edits = edits
 6190                        .into_iter()
 6191                        .map(|(range, text)| {
 6192                            use text::ToPoint as TP;
 6193                            let end_point = TP::to_point(&range.end, &snapshot);
 6194                            let start_point = TP::to_point(&range.start, &snapshot);
 6195                            (start_point..end_point, text)
 6196                        })
 6197                        .sorted_by_key(|(range, _)| range.start);
 6198                    buffer.edit(edits, None, cx);
 6199                })
 6200            }
 6201
 6202            editor.refresh_edit_prediction(true, false, window, cx);
 6203        });
 6204        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6205
 6206        let show_new_completions_on_confirm = completion
 6207            .confirm
 6208            .as_ref()
 6209            .is_some_and(|confirm| confirm(intent, window, cx));
 6210        if show_new_completions_on_confirm {
 6211            self.open_or_update_completions_menu(None, None, false, window, cx);
 6212        }
 6213
 6214        let provider = self.completion_provider.as_ref()?;
 6215
 6216        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6217        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6218            let CompletionSource::Lsp {
 6219                lsp_completion,
 6220                server_id,
 6221                ..
 6222            } = &completion.source
 6223            else {
 6224                return None;
 6225            };
 6226            let lsp_command = lsp_completion.command.as_ref()?;
 6227            let available_commands = lsp_store
 6228                .read(cx)
 6229                .lsp_server_capabilities
 6230                .get(server_id)
 6231                .and_then(|server_capabilities| {
 6232                    server_capabilities
 6233                        .execute_command_provider
 6234                        .as_ref()
 6235                        .map(|options| options.commands.as_slice())
 6236                })?;
 6237            if available_commands.contains(&lsp_command.command) {
 6238                Some(CodeAction {
 6239                    server_id: *server_id,
 6240                    range: language::Anchor::MIN..language::Anchor::MIN,
 6241                    lsp_action: LspAction::Command(lsp_command.clone()),
 6242                    resolved: false,
 6243                })
 6244            } else {
 6245                None
 6246            }
 6247        });
 6248
 6249        drop(completion);
 6250        let apply_edits = provider.apply_additional_edits_for_completion(
 6251            buffer_handle.clone(),
 6252            completions_menu.completions.clone(),
 6253            candidate_id,
 6254            true,
 6255            cx,
 6256        );
 6257
 6258        let editor_settings = EditorSettings::get_global(cx);
 6259        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6260            // After the code completion is finished, users often want to know what signatures are needed.
 6261            // so we should automatically call signature_help
 6262            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6263        }
 6264
 6265        Some(cx.spawn_in(window, async move |editor, cx| {
 6266            apply_edits.await?;
 6267
 6268            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6269                let title = command.lsp_action.title().to_owned();
 6270                let project_transaction = lsp_store
 6271                    .update(cx, |lsp_store, cx| {
 6272                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6273                    })?
 6274                    .await
 6275                    .context("applying post-completion command")?;
 6276                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6277                    Self::open_project_transaction(
 6278                        &editor,
 6279                        workspace.downgrade(),
 6280                        project_transaction,
 6281                        title,
 6282                        cx,
 6283                    )
 6284                    .await?;
 6285                }
 6286            }
 6287
 6288            Ok(())
 6289        }))
 6290    }
 6291
 6292    pub fn toggle_code_actions(
 6293        &mut self,
 6294        action: &ToggleCodeActions,
 6295        window: &mut Window,
 6296        cx: &mut Context<Self>,
 6297    ) {
 6298        let quick_launch = action.quick_launch;
 6299        let mut context_menu = self.context_menu.borrow_mut();
 6300        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6301            if code_actions.deployed_from == action.deployed_from {
 6302                // Toggle if we're selecting the same one
 6303                *context_menu = None;
 6304                cx.notify();
 6305                return;
 6306            } else {
 6307                // Otherwise, clear it and start a new one
 6308                *context_menu = None;
 6309                cx.notify();
 6310            }
 6311        }
 6312        drop(context_menu);
 6313        let snapshot = self.snapshot(window, cx);
 6314        let deployed_from = action.deployed_from.clone();
 6315        let action = action.clone();
 6316        self.completion_tasks.clear();
 6317        self.discard_edit_prediction(false, cx);
 6318
 6319        let multibuffer_point = match &action.deployed_from {
 6320            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6321                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6322            }
 6323            _ => self
 6324                .selections
 6325                .newest::<Point>(&snapshot.display_snapshot)
 6326                .head(),
 6327        };
 6328        let Some((buffer, buffer_row)) = snapshot
 6329            .buffer_snapshot()
 6330            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6331            .and_then(|(buffer_snapshot, range)| {
 6332                self.buffer()
 6333                    .read(cx)
 6334                    .buffer(buffer_snapshot.remote_id())
 6335                    .map(|buffer| (buffer, range.start.row))
 6336            })
 6337        else {
 6338            return;
 6339        };
 6340        let buffer_id = buffer.read(cx).remote_id();
 6341        let tasks = self
 6342            .tasks
 6343            .get(&(buffer_id, buffer_row))
 6344            .map(|t| Arc::new(t.to_owned()));
 6345
 6346        if !self.focus_handle.is_focused(window) {
 6347            return;
 6348        }
 6349        let project = self.project.clone();
 6350
 6351        let code_actions_task = match deployed_from {
 6352            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6353            _ => self.code_actions(buffer_row, window, cx),
 6354        };
 6355
 6356        let runnable_task = match deployed_from {
 6357            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6358            _ => {
 6359                let mut task_context_task = Task::ready(None);
 6360                if let Some(tasks) = &tasks
 6361                    && let Some(project) = project
 6362                {
 6363                    task_context_task =
 6364                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6365                }
 6366
 6367                cx.spawn_in(window, {
 6368                    let buffer = buffer.clone();
 6369                    async move |editor, cx| {
 6370                        let task_context = task_context_task.await;
 6371
 6372                        let resolved_tasks =
 6373                            tasks
 6374                                .zip(task_context.clone())
 6375                                .map(|(tasks, task_context)| ResolvedTasks {
 6376                                    templates: tasks.resolve(&task_context).collect(),
 6377                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6378                                        multibuffer_point.row,
 6379                                        tasks.column,
 6380                                    )),
 6381                                });
 6382                        let debug_scenarios = editor
 6383                            .update(cx, |editor, cx| {
 6384                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6385                            })?
 6386                            .await;
 6387                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6388                    }
 6389                })
 6390            }
 6391        };
 6392
 6393        cx.spawn_in(window, async move |editor, cx| {
 6394            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6395            let code_actions = code_actions_task.await;
 6396            let spawn_straight_away = quick_launch
 6397                && resolved_tasks
 6398                    .as_ref()
 6399                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6400                && code_actions
 6401                    .as_ref()
 6402                    .is_none_or(|actions| actions.is_empty())
 6403                && debug_scenarios.is_empty();
 6404
 6405            editor.update_in(cx, |editor, window, cx| {
 6406                crate::hover_popover::hide_hover(editor, cx);
 6407                let actions = CodeActionContents::new(
 6408                    resolved_tasks,
 6409                    code_actions,
 6410                    debug_scenarios,
 6411                    task_context.unwrap_or_default(),
 6412                );
 6413
 6414                // Don't show the menu if there are no actions available
 6415                if actions.is_empty() {
 6416                    cx.notify();
 6417                    return Task::ready(Ok(()));
 6418                }
 6419
 6420                *editor.context_menu.borrow_mut() =
 6421                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6422                        buffer,
 6423                        actions,
 6424                        selected_item: Default::default(),
 6425                        scroll_handle: UniformListScrollHandle::default(),
 6426                        deployed_from,
 6427                    }));
 6428                cx.notify();
 6429                if spawn_straight_away
 6430                    && let Some(task) = editor.confirm_code_action(
 6431                        &ConfirmCodeAction { item_ix: Some(0) },
 6432                        window,
 6433                        cx,
 6434                    )
 6435                {
 6436                    return task;
 6437                }
 6438
 6439                Task::ready(Ok(()))
 6440            })
 6441        })
 6442        .detach_and_log_err(cx);
 6443    }
 6444
 6445    fn debug_scenarios(
 6446        &mut self,
 6447        resolved_tasks: &Option<ResolvedTasks>,
 6448        buffer: &Entity<Buffer>,
 6449        cx: &mut App,
 6450    ) -> Task<Vec<task::DebugScenario>> {
 6451        maybe!({
 6452            let project = self.project()?;
 6453            let dap_store = project.read(cx).dap_store();
 6454            let mut scenarios = vec![];
 6455            let resolved_tasks = resolved_tasks.as_ref()?;
 6456            let buffer = buffer.read(cx);
 6457            let language = buffer.language()?;
 6458            let file = buffer.file();
 6459            let debug_adapter = language_settings(language.name().into(), file, cx)
 6460                .debuggers
 6461                .first()
 6462                .map(SharedString::from)
 6463                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6464
 6465            dap_store.update(cx, |dap_store, cx| {
 6466                for (_, task) in &resolved_tasks.templates {
 6467                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6468                        task.original_task().clone(),
 6469                        debug_adapter.clone().into(),
 6470                        task.display_label().to_owned().into(),
 6471                        cx,
 6472                    );
 6473                    scenarios.push(maybe_scenario);
 6474                }
 6475            });
 6476            Some(cx.background_spawn(async move {
 6477                futures::future::join_all(scenarios)
 6478                    .await
 6479                    .into_iter()
 6480                    .flatten()
 6481                    .collect::<Vec<_>>()
 6482            }))
 6483        })
 6484        .unwrap_or_else(|| Task::ready(vec![]))
 6485    }
 6486
 6487    fn code_actions(
 6488        &mut self,
 6489        buffer_row: u32,
 6490        window: &mut Window,
 6491        cx: &mut Context<Self>,
 6492    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6493        let mut task = self.code_actions_task.take();
 6494        cx.spawn_in(window, async move |editor, cx| {
 6495            while let Some(prev_task) = task {
 6496                prev_task.await.log_err();
 6497                task = editor
 6498                    .update(cx, |this, _| this.code_actions_task.take())
 6499                    .ok()?;
 6500            }
 6501
 6502            editor
 6503                .update(cx, |editor, cx| {
 6504                    editor
 6505                        .available_code_actions
 6506                        .clone()
 6507                        .and_then(|(location, code_actions)| {
 6508                            let snapshot = location.buffer.read(cx).snapshot();
 6509                            let point_range = location.range.to_point(&snapshot);
 6510                            let point_range = point_range.start.row..=point_range.end.row;
 6511                            if point_range.contains(&buffer_row) {
 6512                                Some(code_actions)
 6513                            } else {
 6514                                None
 6515                            }
 6516                        })
 6517                })
 6518                .ok()
 6519                .flatten()
 6520        })
 6521    }
 6522
 6523    pub fn confirm_code_action(
 6524        &mut self,
 6525        action: &ConfirmCodeAction,
 6526        window: &mut Window,
 6527        cx: &mut Context<Self>,
 6528    ) -> Option<Task<Result<()>>> {
 6529        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6530
 6531        let actions_menu =
 6532            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6533                menu
 6534            } else {
 6535                return None;
 6536            };
 6537
 6538        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6539        let action = actions_menu.actions.get(action_ix)?;
 6540        let title = action.label();
 6541        let buffer = actions_menu.buffer;
 6542        let workspace = self.workspace()?;
 6543
 6544        match action {
 6545            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6546                workspace.update(cx, |workspace, cx| {
 6547                    workspace.schedule_resolved_task(
 6548                        task_source_kind,
 6549                        resolved_task,
 6550                        false,
 6551                        window,
 6552                        cx,
 6553                    );
 6554
 6555                    Some(Task::ready(Ok(())))
 6556                })
 6557            }
 6558            CodeActionsItem::CodeAction {
 6559                excerpt_id,
 6560                action,
 6561                provider,
 6562            } => {
 6563                let apply_code_action =
 6564                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6565                let workspace = workspace.downgrade();
 6566                Some(cx.spawn_in(window, async move |editor, cx| {
 6567                    let project_transaction = apply_code_action.await?;
 6568                    Self::open_project_transaction(
 6569                        &editor,
 6570                        workspace,
 6571                        project_transaction,
 6572                        title,
 6573                        cx,
 6574                    )
 6575                    .await
 6576                }))
 6577            }
 6578            CodeActionsItem::DebugScenario(scenario) => {
 6579                let context = actions_menu.actions.context;
 6580
 6581                workspace.update(cx, |workspace, cx| {
 6582                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6583                    workspace.start_debug_session(
 6584                        scenario,
 6585                        context,
 6586                        Some(buffer),
 6587                        None,
 6588                        window,
 6589                        cx,
 6590                    );
 6591                });
 6592                Some(Task::ready(Ok(())))
 6593            }
 6594        }
 6595    }
 6596
 6597    pub async fn open_project_transaction(
 6598        editor: &WeakEntity<Editor>,
 6599        workspace: WeakEntity<Workspace>,
 6600        transaction: ProjectTransaction,
 6601        title: String,
 6602        cx: &mut AsyncWindowContext,
 6603    ) -> Result<()> {
 6604        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6605        cx.update(|_, cx| {
 6606            entries.sort_unstable_by_key(|(buffer, _)| {
 6607                buffer.read(cx).file().map(|f| f.path().clone())
 6608            });
 6609        })?;
 6610        if entries.is_empty() {
 6611            return Ok(());
 6612        }
 6613
 6614        // If the project transaction's edits are all contained within this editor, then
 6615        // avoid opening a new editor to display them.
 6616
 6617        if let [(buffer, transaction)] = &*entries {
 6618            let excerpt = editor.update(cx, |editor, cx| {
 6619                editor
 6620                    .buffer()
 6621                    .read(cx)
 6622                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6623            })?;
 6624            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6625                && excerpted_buffer == *buffer
 6626            {
 6627                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6628                    let excerpt_range = excerpt_range.to_offset(buffer);
 6629                    buffer
 6630                        .edited_ranges_for_transaction::<usize>(transaction)
 6631                        .all(|range| {
 6632                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6633                        })
 6634                })?;
 6635
 6636                if all_edits_within_excerpt {
 6637                    return Ok(());
 6638                }
 6639            }
 6640        }
 6641
 6642        let mut ranges_to_highlight = Vec::new();
 6643        let excerpt_buffer = cx.new(|cx| {
 6644            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6645            for (buffer_handle, transaction) in &entries {
 6646                let edited_ranges = buffer_handle
 6647                    .read(cx)
 6648                    .edited_ranges_for_transaction::<Point>(transaction)
 6649                    .collect::<Vec<_>>();
 6650                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6651                    PathKey::for_buffer(buffer_handle, cx),
 6652                    buffer_handle.clone(),
 6653                    edited_ranges,
 6654                    multibuffer_context_lines(cx),
 6655                    cx,
 6656                );
 6657
 6658                ranges_to_highlight.extend(ranges);
 6659            }
 6660            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6661            multibuffer
 6662        })?;
 6663
 6664        workspace.update_in(cx, |workspace, window, cx| {
 6665            let project = workspace.project().clone();
 6666            let editor =
 6667                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6668            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6669            editor.update(cx, |editor, cx| {
 6670                editor.highlight_background::<Self>(
 6671                    &ranges_to_highlight,
 6672                    |_, theme| theme.colors().editor_highlighted_line_background,
 6673                    cx,
 6674                );
 6675            });
 6676        })?;
 6677
 6678        Ok(())
 6679    }
 6680
 6681    pub fn clear_code_action_providers(&mut self) {
 6682        self.code_action_providers.clear();
 6683        self.available_code_actions.take();
 6684    }
 6685
 6686    pub fn add_code_action_provider(
 6687        &mut self,
 6688        provider: Rc<dyn CodeActionProvider>,
 6689        window: &mut Window,
 6690        cx: &mut Context<Self>,
 6691    ) {
 6692        if self
 6693            .code_action_providers
 6694            .iter()
 6695            .any(|existing_provider| existing_provider.id() == provider.id())
 6696        {
 6697            return;
 6698        }
 6699
 6700        self.code_action_providers.push(provider);
 6701        self.refresh_code_actions(window, cx);
 6702    }
 6703
 6704    pub fn remove_code_action_provider(
 6705        &mut self,
 6706        id: Arc<str>,
 6707        window: &mut Window,
 6708        cx: &mut Context<Self>,
 6709    ) {
 6710        self.code_action_providers
 6711            .retain(|provider| provider.id() != id);
 6712        self.refresh_code_actions(window, cx);
 6713    }
 6714
 6715    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6716        !self.code_action_providers.is_empty()
 6717            && EditorSettings::get_global(cx).toolbar.code_actions
 6718    }
 6719
 6720    pub fn has_available_code_actions(&self) -> bool {
 6721        self.available_code_actions
 6722            .as_ref()
 6723            .is_some_and(|(_, actions)| !actions.is_empty())
 6724    }
 6725
 6726    fn render_inline_code_actions(
 6727        &self,
 6728        icon_size: ui::IconSize,
 6729        display_row: DisplayRow,
 6730        is_active: bool,
 6731        cx: &mut Context<Self>,
 6732    ) -> AnyElement {
 6733        let show_tooltip = !self.context_menu_visible();
 6734        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6735            .icon_size(icon_size)
 6736            .shape(ui::IconButtonShape::Square)
 6737            .icon_color(ui::Color::Hidden)
 6738            .toggle_state(is_active)
 6739            .when(show_tooltip, |this| {
 6740                this.tooltip({
 6741                    let focus_handle = self.focus_handle.clone();
 6742                    move |_window, cx| {
 6743                        Tooltip::for_action_in(
 6744                            "Toggle Code Actions",
 6745                            &ToggleCodeActions {
 6746                                deployed_from: None,
 6747                                quick_launch: false,
 6748                            },
 6749                            &focus_handle,
 6750                            cx,
 6751                        )
 6752                    }
 6753                })
 6754            })
 6755            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6756                window.focus(&editor.focus_handle(cx));
 6757                editor.toggle_code_actions(
 6758                    &crate::actions::ToggleCodeActions {
 6759                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6760                            display_row,
 6761                        )),
 6762                        quick_launch: false,
 6763                    },
 6764                    window,
 6765                    cx,
 6766                );
 6767            }))
 6768            .into_any_element()
 6769    }
 6770
 6771    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6772        &self.context_menu
 6773    }
 6774
 6775    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6776        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6777            cx.background_executor()
 6778                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6779                .await;
 6780
 6781            let (start_buffer, start, _, end, newest_selection) = this
 6782                .update(cx, |this, cx| {
 6783                    let newest_selection = this.selections.newest_anchor().clone();
 6784                    if newest_selection.head().diff_base_anchor.is_some() {
 6785                        return None;
 6786                    }
 6787                    let display_snapshot = this.display_snapshot(cx);
 6788                    let newest_selection_adjusted =
 6789                        this.selections.newest_adjusted(&display_snapshot);
 6790                    let buffer = this.buffer.read(cx);
 6791
 6792                    let (start_buffer, start) =
 6793                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6794                    let (end_buffer, end) =
 6795                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6796
 6797                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6798                })?
 6799                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6800                .context(
 6801                    "Expected selection to lie in a single buffer when refreshing code actions",
 6802                )?;
 6803            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6804                let providers = this.code_action_providers.clone();
 6805                let tasks = this
 6806                    .code_action_providers
 6807                    .iter()
 6808                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6809                    .collect::<Vec<_>>();
 6810                (providers, tasks)
 6811            })?;
 6812
 6813            let mut actions = Vec::new();
 6814            for (provider, provider_actions) in
 6815                providers.into_iter().zip(future::join_all(tasks).await)
 6816            {
 6817                if let Some(provider_actions) = provider_actions.log_err() {
 6818                    actions.extend(provider_actions.into_iter().map(|action| {
 6819                        AvailableCodeAction {
 6820                            excerpt_id: newest_selection.start.excerpt_id,
 6821                            action,
 6822                            provider: provider.clone(),
 6823                        }
 6824                    }));
 6825                }
 6826            }
 6827
 6828            this.update(cx, |this, cx| {
 6829                this.available_code_actions = if actions.is_empty() {
 6830                    None
 6831                } else {
 6832                    Some((
 6833                        Location {
 6834                            buffer: start_buffer,
 6835                            range: start..end,
 6836                        },
 6837                        actions.into(),
 6838                    ))
 6839                };
 6840                cx.notify();
 6841            })
 6842        }));
 6843    }
 6844
 6845    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6846        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6847            self.show_git_blame_inline = false;
 6848
 6849            self.show_git_blame_inline_delay_task =
 6850                Some(cx.spawn_in(window, async move |this, cx| {
 6851                    cx.background_executor().timer(delay).await;
 6852
 6853                    this.update(cx, |this, cx| {
 6854                        this.show_git_blame_inline = true;
 6855                        cx.notify();
 6856                    })
 6857                    .log_err();
 6858                }));
 6859        }
 6860    }
 6861
 6862    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6863        let snapshot = self.snapshot(window, cx);
 6864        let cursor = self
 6865            .selections
 6866            .newest::<Point>(&snapshot.display_snapshot)
 6867            .head();
 6868        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6869        else {
 6870            return;
 6871        };
 6872
 6873        if self.blame.is_none() {
 6874            self.start_git_blame(true, window, cx);
 6875        }
 6876        let Some(blame) = self.blame.as_ref() else {
 6877            return;
 6878        };
 6879
 6880        let row_info = RowInfo {
 6881            buffer_id: Some(buffer.remote_id()),
 6882            buffer_row: Some(point.row),
 6883            ..Default::default()
 6884        };
 6885        let Some((buffer, blame_entry)) = blame
 6886            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6887            .flatten()
 6888        else {
 6889            return;
 6890        };
 6891
 6892        let anchor = self.selections.newest_anchor().head();
 6893        let position = self.to_pixel_point(anchor, &snapshot, window);
 6894        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6895            self.show_blame_popover(
 6896                buffer,
 6897                &blame_entry,
 6898                position + last_bounds.origin,
 6899                true,
 6900                cx,
 6901            );
 6902        };
 6903    }
 6904
 6905    fn show_blame_popover(
 6906        &mut self,
 6907        buffer: BufferId,
 6908        blame_entry: &BlameEntry,
 6909        position: gpui::Point<Pixels>,
 6910        ignore_timeout: bool,
 6911        cx: &mut Context<Self>,
 6912    ) {
 6913        if let Some(state) = &mut self.inline_blame_popover {
 6914            state.hide_task.take();
 6915        } else {
 6916            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6917            let blame_entry = blame_entry.clone();
 6918            let show_task = cx.spawn(async move |editor, cx| {
 6919                if !ignore_timeout {
 6920                    cx.background_executor()
 6921                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6922                        .await;
 6923                }
 6924                editor
 6925                    .update(cx, |editor, cx| {
 6926                        editor.inline_blame_popover_show_task.take();
 6927                        let Some(blame) = editor.blame.as_ref() else {
 6928                            return;
 6929                        };
 6930                        let blame = blame.read(cx);
 6931                        let details = blame.details_for_entry(buffer, &blame_entry);
 6932                        let markdown = cx.new(|cx| {
 6933                            Markdown::new(
 6934                                details
 6935                                    .as_ref()
 6936                                    .map(|message| message.message.clone())
 6937                                    .unwrap_or_default(),
 6938                                None,
 6939                                None,
 6940                                cx,
 6941                            )
 6942                        });
 6943                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6944                            position,
 6945                            hide_task: None,
 6946                            popover_bounds: None,
 6947                            popover_state: InlineBlamePopoverState {
 6948                                scroll_handle: ScrollHandle::new(),
 6949                                commit_message: details,
 6950                                markdown,
 6951                            },
 6952                            keyboard_grace: ignore_timeout,
 6953                        });
 6954                        cx.notify();
 6955                    })
 6956                    .ok();
 6957            });
 6958            self.inline_blame_popover_show_task = Some(show_task);
 6959        }
 6960    }
 6961
 6962    pub fn has_mouse_context_menu(&self) -> bool {
 6963        self.mouse_context_menu.is_some()
 6964    }
 6965
 6966    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6967        self.inline_blame_popover_show_task.take();
 6968        if let Some(state) = &mut self.inline_blame_popover {
 6969            let hide_task = cx.spawn(async move |editor, cx| {
 6970                if !ignore_timeout {
 6971                    cx.background_executor()
 6972                        .timer(std::time::Duration::from_millis(100))
 6973                        .await;
 6974                }
 6975                editor
 6976                    .update(cx, |editor, cx| {
 6977                        editor.inline_blame_popover.take();
 6978                        cx.notify();
 6979                    })
 6980                    .ok();
 6981            });
 6982            state.hide_task = Some(hide_task);
 6983            true
 6984        } else {
 6985            false
 6986        }
 6987    }
 6988
 6989    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6990        if self.pending_rename.is_some() {
 6991            return None;
 6992        }
 6993
 6994        let provider = self.semantics_provider.clone()?;
 6995        let buffer = self.buffer.read(cx);
 6996        let newest_selection = self.selections.newest_anchor().clone();
 6997        let cursor_position = newest_selection.head();
 6998        let (cursor_buffer, cursor_buffer_position) =
 6999            buffer.text_anchor_for_position(cursor_position, cx)?;
 7000        let (tail_buffer, tail_buffer_position) =
 7001            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7002        if cursor_buffer != tail_buffer {
 7003            return None;
 7004        }
 7005
 7006        let snapshot = cursor_buffer.read(cx).snapshot();
 7007        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7008        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7009        if start_word_range != end_word_range {
 7010            self.document_highlights_task.take();
 7011            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7012            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7013            return None;
 7014        }
 7015
 7016        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7017        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7018            cx.background_executor()
 7019                .timer(Duration::from_millis(debounce))
 7020                .await;
 7021
 7022            let highlights = if let Some(highlights) = cx
 7023                .update(|cx| {
 7024                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7025                })
 7026                .ok()
 7027                .flatten()
 7028            {
 7029                highlights.await.log_err()
 7030            } else {
 7031                None
 7032            };
 7033
 7034            if let Some(highlights) = highlights {
 7035                this.update(cx, |this, cx| {
 7036                    if this.pending_rename.is_some() {
 7037                        return;
 7038                    }
 7039
 7040                    let buffer = this.buffer.read(cx);
 7041                    if buffer
 7042                        .text_anchor_for_position(cursor_position, cx)
 7043                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7044                    {
 7045                        return;
 7046                    }
 7047
 7048                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7049                    let mut write_ranges = Vec::new();
 7050                    let mut read_ranges = Vec::new();
 7051                    for highlight in highlights {
 7052                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7053                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7054                        {
 7055                            let start = highlight
 7056                                .range
 7057                                .start
 7058                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7059                            let end = highlight
 7060                                .range
 7061                                .end
 7062                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7063                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7064                                continue;
 7065                            }
 7066
 7067                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7068                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7069                                write_ranges.push(range);
 7070                            } else {
 7071                                read_ranges.push(range);
 7072                            }
 7073                        }
 7074                    }
 7075
 7076                    this.highlight_background::<DocumentHighlightRead>(
 7077                        &read_ranges,
 7078                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7079                        cx,
 7080                    );
 7081                    this.highlight_background::<DocumentHighlightWrite>(
 7082                        &write_ranges,
 7083                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7084                        cx,
 7085                    );
 7086                    cx.notify();
 7087                })
 7088                .log_err();
 7089            }
 7090        }));
 7091        None
 7092    }
 7093
 7094    fn prepare_highlight_query_from_selection(
 7095        &mut self,
 7096        window: &Window,
 7097        cx: &mut Context<Editor>,
 7098    ) -> Option<(String, Range<Anchor>)> {
 7099        if matches!(self.mode, EditorMode::SingleLine) {
 7100            return None;
 7101        }
 7102        if !EditorSettings::get_global(cx).selection_highlight {
 7103            return None;
 7104        }
 7105        if self.selections.count() != 1 || self.selections.line_mode() {
 7106            return None;
 7107        }
 7108        let snapshot = self.snapshot(window, cx);
 7109        let selection = self.selections.newest::<Point>(&snapshot);
 7110        // If the selection spans multiple rows OR it is empty
 7111        if selection.start.row != selection.end.row
 7112            || selection.start.column == selection.end.column
 7113        {
 7114            return None;
 7115        }
 7116        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7117        let query = snapshot
 7118            .buffer_snapshot()
 7119            .text_for_range(selection_anchor_range.clone())
 7120            .collect::<String>();
 7121        if query.trim().is_empty() {
 7122            return None;
 7123        }
 7124        Some((query, selection_anchor_range))
 7125    }
 7126
 7127    fn update_selection_occurrence_highlights(
 7128        &mut self,
 7129        query_text: String,
 7130        query_range: Range<Anchor>,
 7131        multi_buffer_range_to_query: Range<Point>,
 7132        use_debounce: bool,
 7133        window: &mut Window,
 7134        cx: &mut Context<Editor>,
 7135    ) -> Task<()> {
 7136        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7137        cx.spawn_in(window, async move |editor, cx| {
 7138            if use_debounce {
 7139                cx.background_executor()
 7140                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7141                    .await;
 7142            }
 7143            let match_task = cx.background_spawn(async move {
 7144                let buffer_ranges = multi_buffer_snapshot
 7145                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7146                    .into_iter()
 7147                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7148                let mut match_ranges = Vec::new();
 7149                let Ok(regex) = project::search::SearchQuery::text(
 7150                    query_text.clone(),
 7151                    false,
 7152                    false,
 7153                    false,
 7154                    Default::default(),
 7155                    Default::default(),
 7156                    false,
 7157                    None,
 7158                ) else {
 7159                    return Vec::default();
 7160                };
 7161                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7162                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7163                    match_ranges.extend(
 7164                        regex
 7165                            .search(
 7166                                buffer_snapshot,
 7167                                Some(search_range.start.0..search_range.end.0),
 7168                            )
 7169                            .await
 7170                            .into_iter()
 7171                            .filter_map(|match_range| {
 7172                                let match_start = buffer_snapshot
 7173                                    .anchor_after(search_range.start + match_range.start);
 7174                                let match_end = buffer_snapshot
 7175                                    .anchor_before(search_range.start + match_range.end);
 7176                                let match_anchor_range =
 7177                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7178                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7179                            }),
 7180                    );
 7181                }
 7182                match_ranges
 7183            });
 7184            let match_ranges = match_task.await;
 7185            editor
 7186                .update_in(cx, |editor, _, cx| {
 7187                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7188                    if !match_ranges.is_empty() {
 7189                        editor.highlight_background::<SelectedTextHighlight>(
 7190                            &match_ranges,
 7191                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7192                            cx,
 7193                        )
 7194                    }
 7195                })
 7196                .log_err();
 7197        })
 7198    }
 7199
 7200    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7201        struct NewlineFold;
 7202        let type_id = std::any::TypeId::of::<NewlineFold>();
 7203        if !self.mode.is_single_line() {
 7204            return;
 7205        }
 7206        let snapshot = self.snapshot(window, cx);
 7207        if snapshot.buffer_snapshot().max_point().row == 0 {
 7208            return;
 7209        }
 7210        let task = cx.background_spawn(async move {
 7211            let new_newlines = snapshot
 7212                .buffer_chars_at(MultiBufferOffset(0))
 7213                .filter_map(|(c, i)| {
 7214                    if c == '\n' {
 7215                        Some(
 7216                            snapshot.buffer_snapshot().anchor_after(i)
 7217                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7218                        )
 7219                    } else {
 7220                        None
 7221                    }
 7222                })
 7223                .collect::<Vec<_>>();
 7224            let existing_newlines = snapshot
 7225                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7226                .filter_map(|fold| {
 7227                    if fold.placeholder.type_tag == Some(type_id) {
 7228                        Some(fold.range.start..fold.range.end)
 7229                    } else {
 7230                        None
 7231                    }
 7232                })
 7233                .collect::<Vec<_>>();
 7234
 7235            (new_newlines, existing_newlines)
 7236        });
 7237        self.folding_newlines = cx.spawn(async move |this, cx| {
 7238            let (new_newlines, existing_newlines) = task.await;
 7239            if new_newlines == existing_newlines {
 7240                return;
 7241            }
 7242            let placeholder = FoldPlaceholder {
 7243                render: Arc::new(move |_, _, cx| {
 7244                    div()
 7245                        .bg(cx.theme().status().hint_background)
 7246                        .border_b_1()
 7247                        .size_full()
 7248                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7249                        .border_color(cx.theme().status().hint)
 7250                        .child("\\n")
 7251                        .into_any()
 7252                }),
 7253                constrain_width: false,
 7254                merge_adjacent: false,
 7255                type_tag: Some(type_id),
 7256            };
 7257            let creases = new_newlines
 7258                .into_iter()
 7259                .map(|range| Crease::simple(range, placeholder.clone()))
 7260                .collect();
 7261            this.update(cx, |this, cx| {
 7262                this.display_map.update(cx, |display_map, cx| {
 7263                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7264                    display_map.fold(creases, cx);
 7265                });
 7266            })
 7267            .ok();
 7268        });
 7269    }
 7270
 7271    fn refresh_selected_text_highlights(
 7272        &mut self,
 7273        on_buffer_edit: bool,
 7274        window: &mut Window,
 7275        cx: &mut Context<Editor>,
 7276    ) {
 7277        let Some((query_text, query_range)) =
 7278            self.prepare_highlight_query_from_selection(window, cx)
 7279        else {
 7280            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7281            self.quick_selection_highlight_task.take();
 7282            self.debounced_selection_highlight_task.take();
 7283            return;
 7284        };
 7285        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7286        if on_buffer_edit
 7287            || self
 7288                .quick_selection_highlight_task
 7289                .as_ref()
 7290                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7291        {
 7292            let multi_buffer_visible_start = self
 7293                .scroll_manager
 7294                .anchor()
 7295                .anchor
 7296                .to_point(&multi_buffer_snapshot);
 7297            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7298                multi_buffer_visible_start
 7299                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7300                Bias::Left,
 7301            );
 7302            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7303            self.quick_selection_highlight_task = Some((
 7304                query_range.clone(),
 7305                self.update_selection_occurrence_highlights(
 7306                    query_text.clone(),
 7307                    query_range.clone(),
 7308                    multi_buffer_visible_range,
 7309                    false,
 7310                    window,
 7311                    cx,
 7312                ),
 7313            ));
 7314        }
 7315        if on_buffer_edit
 7316            || self
 7317                .debounced_selection_highlight_task
 7318                .as_ref()
 7319                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7320        {
 7321            let multi_buffer_start = multi_buffer_snapshot
 7322                .anchor_before(MultiBufferOffset(0))
 7323                .to_point(&multi_buffer_snapshot);
 7324            let multi_buffer_end = multi_buffer_snapshot
 7325                .anchor_after(multi_buffer_snapshot.len())
 7326                .to_point(&multi_buffer_snapshot);
 7327            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7328            self.debounced_selection_highlight_task = Some((
 7329                query_range.clone(),
 7330                self.update_selection_occurrence_highlights(
 7331                    query_text,
 7332                    query_range,
 7333                    multi_buffer_full_range,
 7334                    true,
 7335                    window,
 7336                    cx,
 7337                ),
 7338            ));
 7339        }
 7340    }
 7341
 7342    pub fn refresh_edit_prediction(
 7343        &mut self,
 7344        debounce: bool,
 7345        user_requested: bool,
 7346        window: &mut Window,
 7347        cx: &mut Context<Self>,
 7348    ) -> Option<()> {
 7349        if DisableAiSettings::get_global(cx).disable_ai {
 7350            return None;
 7351        }
 7352
 7353        let provider = self.edit_prediction_provider()?;
 7354        let cursor = self.selections.newest_anchor().head();
 7355        let (buffer, cursor_buffer_position) =
 7356            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7357
 7358        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7359            self.discard_edit_prediction(false, cx);
 7360            return None;
 7361        }
 7362
 7363        self.update_visible_edit_prediction(window, cx);
 7364
 7365        if !user_requested
 7366            && (!self.should_show_edit_predictions()
 7367                || !self.is_focused(window)
 7368                || buffer.read(cx).is_empty())
 7369        {
 7370            self.discard_edit_prediction(false, cx);
 7371            return None;
 7372        }
 7373
 7374        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7375        Some(())
 7376    }
 7377
 7378    fn show_edit_predictions_in_menu(&self) -> bool {
 7379        match self.edit_prediction_settings {
 7380            EditPredictionSettings::Disabled => false,
 7381            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7382        }
 7383    }
 7384
 7385    pub fn edit_predictions_enabled(&self) -> bool {
 7386        match self.edit_prediction_settings {
 7387            EditPredictionSettings::Disabled => false,
 7388            EditPredictionSettings::Enabled { .. } => true,
 7389        }
 7390    }
 7391
 7392    fn edit_prediction_requires_modifier(&self) -> bool {
 7393        match self.edit_prediction_settings {
 7394            EditPredictionSettings::Disabled => false,
 7395            EditPredictionSettings::Enabled {
 7396                preview_requires_modifier,
 7397                ..
 7398            } => preview_requires_modifier,
 7399        }
 7400    }
 7401
 7402    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7403        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7404            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7405            self.discard_edit_prediction(false, cx);
 7406        } else {
 7407            let selection = self.selections.newest_anchor();
 7408            let cursor = selection.head();
 7409
 7410            if let Some((buffer, cursor_buffer_position)) =
 7411                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7412            {
 7413                self.edit_prediction_settings =
 7414                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7415            }
 7416        }
 7417    }
 7418
 7419    fn edit_prediction_settings_at_position(
 7420        &self,
 7421        buffer: &Entity<Buffer>,
 7422        buffer_position: language::Anchor,
 7423        cx: &App,
 7424    ) -> EditPredictionSettings {
 7425        if !self.mode.is_full()
 7426            || !self.show_edit_predictions_override.unwrap_or(true)
 7427            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7428        {
 7429            return EditPredictionSettings::Disabled;
 7430        }
 7431
 7432        let buffer = buffer.read(cx);
 7433
 7434        let file = buffer.file();
 7435
 7436        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7437            return EditPredictionSettings::Disabled;
 7438        };
 7439
 7440        let by_provider = matches!(
 7441            self.menu_edit_predictions_policy,
 7442            MenuEditPredictionsPolicy::ByProvider
 7443        );
 7444
 7445        let show_in_menu = by_provider
 7446            && self
 7447                .edit_prediction_provider
 7448                .as_ref()
 7449                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7450
 7451        let preview_requires_modifier =
 7452            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7453
 7454        EditPredictionSettings::Enabled {
 7455            show_in_menu,
 7456            preview_requires_modifier,
 7457        }
 7458    }
 7459
 7460    fn should_show_edit_predictions(&self) -> bool {
 7461        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7462    }
 7463
 7464    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7465        matches!(
 7466            self.edit_prediction_preview,
 7467            EditPredictionPreview::Active { .. }
 7468        )
 7469    }
 7470
 7471    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7472        let cursor = self.selections.newest_anchor().head();
 7473        if let Some((buffer, cursor_position)) =
 7474            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7475        {
 7476            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7477        } else {
 7478            false
 7479        }
 7480    }
 7481
 7482    pub fn supports_minimap(&self, cx: &App) -> bool {
 7483        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7484    }
 7485
 7486    fn edit_predictions_enabled_in_buffer(
 7487        &self,
 7488        buffer: &Entity<Buffer>,
 7489        buffer_position: language::Anchor,
 7490        cx: &App,
 7491    ) -> bool {
 7492        maybe!({
 7493            if self.read_only(cx) {
 7494                return Some(false);
 7495            }
 7496            let provider = self.edit_prediction_provider()?;
 7497            if !provider.is_enabled(buffer, buffer_position, cx) {
 7498                return Some(false);
 7499            }
 7500            let buffer = buffer.read(cx);
 7501            let Some(file) = buffer.file() else {
 7502                return Some(true);
 7503            };
 7504            let settings = all_language_settings(Some(file), cx);
 7505            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7506        })
 7507        .unwrap_or(false)
 7508    }
 7509
 7510    fn cycle_edit_prediction(
 7511        &mut self,
 7512        direction: Direction,
 7513        window: &mut Window,
 7514        cx: &mut Context<Self>,
 7515    ) -> Option<()> {
 7516        let provider = self.edit_prediction_provider()?;
 7517        let cursor = self.selections.newest_anchor().head();
 7518        let (buffer, cursor_buffer_position) =
 7519            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7520        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7521            return None;
 7522        }
 7523
 7524        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7525        self.update_visible_edit_prediction(window, cx);
 7526
 7527        Some(())
 7528    }
 7529
 7530    pub fn show_edit_prediction(
 7531        &mut self,
 7532        _: &ShowEditPrediction,
 7533        window: &mut Window,
 7534        cx: &mut Context<Self>,
 7535    ) {
 7536        if !self.has_active_edit_prediction() {
 7537            self.refresh_edit_prediction(false, true, window, cx);
 7538            return;
 7539        }
 7540
 7541        self.update_visible_edit_prediction(window, cx);
 7542    }
 7543
 7544    pub fn display_cursor_names(
 7545        &mut self,
 7546        _: &DisplayCursorNames,
 7547        window: &mut Window,
 7548        cx: &mut Context<Self>,
 7549    ) {
 7550        self.show_cursor_names(window, cx);
 7551    }
 7552
 7553    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7554        self.show_cursor_names = true;
 7555        cx.notify();
 7556        cx.spawn_in(window, async move |this, cx| {
 7557            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7558            this.update(cx, |this, cx| {
 7559                this.show_cursor_names = false;
 7560                cx.notify()
 7561            })
 7562            .ok()
 7563        })
 7564        .detach();
 7565    }
 7566
 7567    pub fn next_edit_prediction(
 7568        &mut self,
 7569        _: &NextEditPrediction,
 7570        window: &mut Window,
 7571        cx: &mut Context<Self>,
 7572    ) {
 7573        if self.has_active_edit_prediction() {
 7574            self.cycle_edit_prediction(Direction::Next, window, cx);
 7575        } else {
 7576            let is_copilot_disabled = self
 7577                .refresh_edit_prediction(false, true, window, cx)
 7578                .is_none();
 7579            if is_copilot_disabled {
 7580                cx.propagate();
 7581            }
 7582        }
 7583    }
 7584
 7585    pub fn previous_edit_prediction(
 7586        &mut self,
 7587        _: &PreviousEditPrediction,
 7588        window: &mut Window,
 7589        cx: &mut Context<Self>,
 7590    ) {
 7591        if self.has_active_edit_prediction() {
 7592            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7593        } else {
 7594            let is_copilot_disabled = self
 7595                .refresh_edit_prediction(false, true, window, cx)
 7596                .is_none();
 7597            if is_copilot_disabled {
 7598                cx.propagate();
 7599            }
 7600        }
 7601    }
 7602
 7603    pub fn accept_edit_prediction(
 7604        &mut self,
 7605        _: &AcceptEditPrediction,
 7606        window: &mut Window,
 7607        cx: &mut Context<Self>,
 7608    ) {
 7609        if self.show_edit_predictions_in_menu() {
 7610            self.hide_context_menu(window, cx);
 7611        }
 7612
 7613        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7614            return;
 7615        };
 7616
 7617        match &active_edit_prediction.completion {
 7618            EditPrediction::MoveWithin { target, .. } => {
 7619                let target = *target;
 7620
 7621                if let Some(position_map) = &self.last_position_map {
 7622                    if position_map
 7623                        .visible_row_range
 7624                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7625                        || !self.edit_prediction_requires_modifier()
 7626                    {
 7627                        self.unfold_ranges(&[target..target], true, false, cx);
 7628                        // Note that this is also done in vim's handler of the Tab action.
 7629                        self.change_selections(
 7630                            SelectionEffects::scroll(Autoscroll::newest()),
 7631                            window,
 7632                            cx,
 7633                            |selections| {
 7634                                selections.select_anchor_ranges([target..target]);
 7635                            },
 7636                        );
 7637                        self.clear_row_highlights::<EditPredictionPreview>();
 7638
 7639                        self.edit_prediction_preview
 7640                            .set_previous_scroll_position(None);
 7641                    } else {
 7642                        self.edit_prediction_preview
 7643                            .set_previous_scroll_position(Some(
 7644                                position_map.snapshot.scroll_anchor,
 7645                            ));
 7646
 7647                        self.highlight_rows::<EditPredictionPreview>(
 7648                            target..target,
 7649                            cx.theme().colors().editor_highlighted_line_background,
 7650                            RowHighlightOptions {
 7651                                autoscroll: true,
 7652                                ..Default::default()
 7653                            },
 7654                            cx,
 7655                        );
 7656                        self.request_autoscroll(Autoscroll::fit(), cx);
 7657                    }
 7658                }
 7659            }
 7660            EditPrediction::MoveOutside { snapshot, target } => {
 7661                if let Some(workspace) = self.workspace() {
 7662                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7663                        .detach_and_log_err(cx);
 7664                }
 7665            }
 7666            EditPrediction::Edit { edits, .. } => {
 7667                self.report_edit_prediction_event(
 7668                    active_edit_prediction.completion_id.clone(),
 7669                    true,
 7670                    cx,
 7671                );
 7672
 7673                if let Some(provider) = self.edit_prediction_provider() {
 7674                    provider.accept(cx);
 7675                }
 7676
 7677                // Store the transaction ID and selections before applying the edit
 7678                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7679
 7680                let snapshot = self.buffer.read(cx).snapshot(cx);
 7681                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7682
 7683                self.buffer.update(cx, |buffer, cx| {
 7684                    buffer.edit(edits.iter().cloned(), None, cx)
 7685                });
 7686
 7687                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7688                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7689                });
 7690
 7691                let selections = self.selections.disjoint_anchors_arc();
 7692                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7693                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7694                    if has_new_transaction {
 7695                        self.selection_history
 7696                            .insert_transaction(transaction_id_now, selections);
 7697                    }
 7698                }
 7699
 7700                self.update_visible_edit_prediction(window, cx);
 7701                if self.active_edit_prediction.is_none() {
 7702                    self.refresh_edit_prediction(true, true, window, cx);
 7703                }
 7704
 7705                cx.notify();
 7706            }
 7707        }
 7708
 7709        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7710    }
 7711
 7712    pub fn accept_partial_edit_prediction(
 7713        &mut self,
 7714        _: &AcceptPartialEditPrediction,
 7715        window: &mut Window,
 7716        cx: &mut Context<Self>,
 7717    ) {
 7718        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7719            return;
 7720        };
 7721        if self.selections.count() != 1 {
 7722            return;
 7723        }
 7724
 7725        match &active_edit_prediction.completion {
 7726            EditPrediction::MoveWithin { target, .. } => {
 7727                let target = *target;
 7728                self.change_selections(
 7729                    SelectionEffects::scroll(Autoscroll::newest()),
 7730                    window,
 7731                    cx,
 7732                    |selections| {
 7733                        selections.select_anchor_ranges([target..target]);
 7734                    },
 7735                );
 7736            }
 7737            EditPrediction::MoveOutside { snapshot, target } => {
 7738                if let Some(workspace) = self.workspace() {
 7739                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7740                        .detach_and_log_err(cx);
 7741                }
 7742            }
 7743            EditPrediction::Edit { edits, .. } => {
 7744                self.report_edit_prediction_event(
 7745                    active_edit_prediction.completion_id.clone(),
 7746                    true,
 7747                    cx,
 7748                );
 7749
 7750                // Find an insertion that starts at the cursor position.
 7751                let snapshot = self.buffer.read(cx).snapshot(cx);
 7752                let cursor_offset = self
 7753                    .selections
 7754                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7755                    .head();
 7756                let insertion = edits.iter().find_map(|(range, text)| {
 7757                    let range = range.to_offset(&snapshot);
 7758                    if range.is_empty() && range.start == cursor_offset {
 7759                        Some(text)
 7760                    } else {
 7761                        None
 7762                    }
 7763                });
 7764
 7765                if let Some(text) = insertion {
 7766                    let mut partial_completion = text
 7767                        .chars()
 7768                        .by_ref()
 7769                        .take_while(|c| c.is_alphabetic())
 7770                        .collect::<String>();
 7771                    if partial_completion.is_empty() {
 7772                        partial_completion = text
 7773                            .chars()
 7774                            .by_ref()
 7775                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7776                            .collect::<String>();
 7777                    }
 7778
 7779                    cx.emit(EditorEvent::InputHandled {
 7780                        utf16_range_to_replace: None,
 7781                        text: partial_completion.clone().into(),
 7782                    });
 7783
 7784                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7785
 7786                    self.refresh_edit_prediction(true, true, window, cx);
 7787                    cx.notify();
 7788                } else {
 7789                    self.accept_edit_prediction(&Default::default(), window, cx);
 7790                }
 7791            }
 7792        }
 7793    }
 7794
 7795    fn discard_edit_prediction(
 7796        &mut self,
 7797        should_report_edit_prediction_event: bool,
 7798        cx: &mut Context<Self>,
 7799    ) -> bool {
 7800        if should_report_edit_prediction_event {
 7801            let completion_id = self
 7802                .active_edit_prediction
 7803                .as_ref()
 7804                .and_then(|active_completion| active_completion.completion_id.clone());
 7805
 7806            self.report_edit_prediction_event(completion_id, false, cx);
 7807        }
 7808
 7809        if let Some(provider) = self.edit_prediction_provider() {
 7810            provider.discard(cx);
 7811        }
 7812
 7813        self.take_active_edit_prediction(cx)
 7814    }
 7815
 7816    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7817        let Some(provider) = self.edit_prediction_provider() else {
 7818            return;
 7819        };
 7820
 7821        let Some((_, buffer, _)) = self
 7822            .buffer
 7823            .read(cx)
 7824            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7825        else {
 7826            return;
 7827        };
 7828
 7829        let extension = buffer
 7830            .read(cx)
 7831            .file()
 7832            .and_then(|file| Some(file.path().extension()?.to_string()));
 7833
 7834        let event_type = match accepted {
 7835            true => "Edit Prediction Accepted",
 7836            false => "Edit Prediction Discarded",
 7837        };
 7838        telemetry::event!(
 7839            event_type,
 7840            provider = provider.name(),
 7841            prediction_id = id,
 7842            suggestion_accepted = accepted,
 7843            file_extension = extension,
 7844        );
 7845    }
 7846
 7847    fn open_editor_at_anchor(
 7848        snapshot: &language::BufferSnapshot,
 7849        target: language::Anchor,
 7850        workspace: &Entity<Workspace>,
 7851        window: &mut Window,
 7852        cx: &mut App,
 7853    ) -> Task<Result<()>> {
 7854        workspace.update(cx, |workspace, cx| {
 7855            let path = snapshot.file().map(|file| file.full_path(cx));
 7856            let Some(path) =
 7857                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7858            else {
 7859                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7860            };
 7861            let target = text::ToPoint::to_point(&target, snapshot);
 7862            let item = workspace.open_path(path, None, true, window, cx);
 7863            window.spawn(cx, async move |cx| {
 7864                let Some(editor) = item.await?.downcast::<Editor>() else {
 7865                    return Ok(());
 7866                };
 7867                editor
 7868                    .update_in(cx, |editor, window, cx| {
 7869                        editor.go_to_singleton_buffer_point(target, window, cx);
 7870                    })
 7871                    .ok();
 7872                anyhow::Ok(())
 7873            })
 7874        })
 7875    }
 7876
 7877    pub fn has_active_edit_prediction(&self) -> bool {
 7878        self.active_edit_prediction.is_some()
 7879    }
 7880
 7881    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7882        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7883            return false;
 7884        };
 7885
 7886        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7887        self.clear_highlights::<EditPredictionHighlight>(cx);
 7888        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7889        true
 7890    }
 7891
 7892    /// Returns true when we're displaying the edit prediction popover below the cursor
 7893    /// like we are not previewing and the LSP autocomplete menu is visible
 7894    /// or we are in `when_holding_modifier` mode.
 7895    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7896        if self.edit_prediction_preview_is_active()
 7897            || !self.show_edit_predictions_in_menu()
 7898            || !self.edit_predictions_enabled()
 7899        {
 7900            return false;
 7901        }
 7902
 7903        if self.has_visible_completions_menu() {
 7904            return true;
 7905        }
 7906
 7907        has_completion && self.edit_prediction_requires_modifier()
 7908    }
 7909
 7910    fn handle_modifiers_changed(
 7911        &mut self,
 7912        modifiers: Modifiers,
 7913        position_map: &PositionMap,
 7914        window: &mut Window,
 7915        cx: &mut Context<Self>,
 7916    ) {
 7917        // Ensure that the edit prediction preview is updated, even when not
 7918        // enabled, if there's an active edit prediction preview.
 7919        if self.show_edit_predictions_in_menu()
 7920            || matches!(
 7921                self.edit_prediction_preview,
 7922                EditPredictionPreview::Active { .. }
 7923            )
 7924        {
 7925            self.update_edit_prediction_preview(&modifiers, window, cx);
 7926        }
 7927
 7928        self.update_selection_mode(&modifiers, position_map, window, cx);
 7929
 7930        let mouse_position = window.mouse_position();
 7931        if !position_map.text_hitbox.is_hovered(window) {
 7932            return;
 7933        }
 7934
 7935        self.update_hovered_link(
 7936            position_map.point_for_position(mouse_position),
 7937            &position_map.snapshot,
 7938            modifiers,
 7939            window,
 7940            cx,
 7941        )
 7942    }
 7943
 7944    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7945        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7946            MultiCursorModifier::Alt => modifiers.secondary(),
 7947            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7948        }
 7949    }
 7950
 7951    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7952        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7953            MultiCursorModifier::Alt => modifiers.alt,
 7954            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7955        }
 7956    }
 7957
 7958    fn columnar_selection_mode(
 7959        modifiers: &Modifiers,
 7960        cx: &mut Context<Self>,
 7961    ) -> Option<ColumnarMode> {
 7962        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7963            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7964                Some(ColumnarMode::FromMouse)
 7965            } else if Self::is_alt_pressed(modifiers, cx) {
 7966                Some(ColumnarMode::FromSelection)
 7967            } else {
 7968                None
 7969            }
 7970        } else {
 7971            None
 7972        }
 7973    }
 7974
 7975    fn update_selection_mode(
 7976        &mut self,
 7977        modifiers: &Modifiers,
 7978        position_map: &PositionMap,
 7979        window: &mut Window,
 7980        cx: &mut Context<Self>,
 7981    ) {
 7982        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7983            return;
 7984        };
 7985        if self.selections.pending_anchor().is_none() {
 7986            return;
 7987        }
 7988
 7989        let mouse_position = window.mouse_position();
 7990        let point_for_position = position_map.point_for_position(mouse_position);
 7991        let position = point_for_position.previous_valid;
 7992
 7993        self.select(
 7994            SelectPhase::BeginColumnar {
 7995                position,
 7996                reset: false,
 7997                mode,
 7998                goal_column: point_for_position.exact_unclipped.column(),
 7999            },
 8000            window,
 8001            cx,
 8002        );
 8003    }
 8004
 8005    fn update_edit_prediction_preview(
 8006        &mut self,
 8007        modifiers: &Modifiers,
 8008        window: &mut Window,
 8009        cx: &mut Context<Self>,
 8010    ) {
 8011        let mut modifiers_held = false;
 8012        if let Some(accept_keystroke) = self
 8013            .accept_edit_prediction_keybind(false, window, cx)
 8014            .keystroke()
 8015        {
 8016            modifiers_held = modifiers_held
 8017                || (accept_keystroke.modifiers() == modifiers
 8018                    && accept_keystroke.modifiers().modified());
 8019        };
 8020        if let Some(accept_partial_keystroke) = self
 8021            .accept_edit_prediction_keybind(true, window, cx)
 8022            .keystroke()
 8023        {
 8024            modifiers_held = modifiers_held
 8025                || (accept_partial_keystroke.modifiers() == modifiers
 8026                    && accept_partial_keystroke.modifiers().modified());
 8027        }
 8028
 8029        if modifiers_held {
 8030            if matches!(
 8031                self.edit_prediction_preview,
 8032                EditPredictionPreview::Inactive { .. }
 8033            ) {
 8034                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 8035                    provider.provider.did_show(cx)
 8036                }
 8037
 8038                self.edit_prediction_preview = EditPredictionPreview::Active {
 8039                    previous_scroll_position: None,
 8040                    since: Instant::now(),
 8041                };
 8042
 8043                self.update_visible_edit_prediction(window, cx);
 8044                cx.notify();
 8045            }
 8046        } else if let EditPredictionPreview::Active {
 8047            previous_scroll_position,
 8048            since,
 8049        } = self.edit_prediction_preview
 8050        {
 8051            if let (Some(previous_scroll_position), Some(position_map)) =
 8052                (previous_scroll_position, self.last_position_map.as_ref())
 8053            {
 8054                self.set_scroll_position(
 8055                    previous_scroll_position
 8056                        .scroll_position(&position_map.snapshot.display_snapshot),
 8057                    window,
 8058                    cx,
 8059                );
 8060            }
 8061
 8062            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8063                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8064            };
 8065            self.clear_row_highlights::<EditPredictionPreview>();
 8066            self.update_visible_edit_prediction(window, cx);
 8067            cx.notify();
 8068        }
 8069    }
 8070
 8071    fn update_visible_edit_prediction(
 8072        &mut self,
 8073        _window: &mut Window,
 8074        cx: &mut Context<Self>,
 8075    ) -> Option<()> {
 8076        if DisableAiSettings::get_global(cx).disable_ai {
 8077            return None;
 8078        }
 8079
 8080        if self.ime_transaction.is_some() {
 8081            self.discard_edit_prediction(false, cx);
 8082            return None;
 8083        }
 8084
 8085        let selection = self.selections.newest_anchor();
 8086        let cursor = selection.head();
 8087        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8088        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8089        let excerpt_id = cursor.excerpt_id;
 8090
 8091        let show_in_menu = self.show_edit_predictions_in_menu();
 8092        let completions_menu_has_precedence = !show_in_menu
 8093            && (self.context_menu.borrow().is_some()
 8094                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8095
 8096        if completions_menu_has_precedence
 8097            || !offset_selection.is_empty()
 8098            || self
 8099                .active_edit_prediction
 8100                .as_ref()
 8101                .is_some_and(|completion| {
 8102                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8103                        return false;
 8104                    };
 8105                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8106                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8107                    !invalidation_range.contains(&offset_selection.head())
 8108                })
 8109        {
 8110            self.discard_edit_prediction(false, cx);
 8111            return None;
 8112        }
 8113
 8114        self.take_active_edit_prediction(cx);
 8115        let Some(provider) = self.edit_prediction_provider() else {
 8116            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8117            return None;
 8118        };
 8119
 8120        let (buffer, cursor_buffer_position) =
 8121            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8122
 8123        self.edit_prediction_settings =
 8124            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8125
 8126        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8127
 8128        if self.edit_prediction_indent_conflict {
 8129            let cursor_point = cursor.to_point(&multibuffer);
 8130            let mut suggested_indent = None;
 8131            multibuffer.suggested_indents_callback(
 8132                cursor_point.row..cursor_point.row + 1,
 8133                |_, indent| {
 8134                    suggested_indent = Some(indent);
 8135                    ControlFlow::Break(())
 8136                },
 8137                cx,
 8138            );
 8139
 8140            if let Some(indent) = suggested_indent
 8141                && indent.len == cursor_point.column
 8142            {
 8143                self.edit_prediction_indent_conflict = false;
 8144            }
 8145        }
 8146
 8147        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8148
 8149        let (completion_id, edits, edit_preview) = match edit_prediction {
 8150            edit_prediction_types::EditPrediction::Local {
 8151                id,
 8152                edits,
 8153                edit_preview,
 8154            } => (id, edits, edit_preview),
 8155            edit_prediction_types::EditPrediction::Jump {
 8156                id,
 8157                snapshot,
 8158                target,
 8159            } => {
 8160                self.stale_edit_prediction_in_menu = None;
 8161                self.active_edit_prediction = Some(EditPredictionState {
 8162                    inlay_ids: vec![],
 8163                    completion: EditPrediction::MoveOutside { snapshot, target },
 8164                    completion_id: id,
 8165                    invalidation_range: None,
 8166                });
 8167                cx.notify();
 8168                return Some(());
 8169            }
 8170        };
 8171
 8172        let edits = edits
 8173            .into_iter()
 8174            .flat_map(|(range, new_text)| {
 8175                Some((
 8176                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8177                    new_text,
 8178                ))
 8179            })
 8180            .collect::<Vec<_>>();
 8181        if edits.is_empty() {
 8182            return None;
 8183        }
 8184
 8185        let first_edit_start = edits.first().unwrap().0.start;
 8186        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8187        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8188
 8189        let last_edit_end = edits.last().unwrap().0.end;
 8190        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8191        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8192
 8193        let cursor_row = cursor.to_point(&multibuffer).row;
 8194
 8195        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8196
 8197        let mut inlay_ids = Vec::new();
 8198        let invalidation_row_range;
 8199        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8200            Some(cursor_row..edit_end_row)
 8201        } else if cursor_row > edit_end_row {
 8202            Some(edit_start_row..cursor_row)
 8203        } else {
 8204            None
 8205        };
 8206        let supports_jump = self
 8207            .edit_prediction_provider
 8208            .as_ref()
 8209            .map(|provider| provider.provider.supports_jump_to_edit())
 8210            .unwrap_or(true);
 8211
 8212        let is_move = supports_jump
 8213            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8214        let completion = if is_move {
 8215            invalidation_row_range =
 8216                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8217            let target = first_edit_start;
 8218            EditPrediction::MoveWithin { target, snapshot }
 8219        } else {
 8220            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8221                && !self.edit_predictions_hidden_for_vim_mode;
 8222
 8223            if show_completions_in_buffer {
 8224                if let Some(provider) = &self.edit_prediction_provider {
 8225                    provider.provider.did_show(cx);
 8226                }
 8227                if edits
 8228                    .iter()
 8229                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8230                {
 8231                    let mut inlays = Vec::new();
 8232                    for (range, new_text) in &edits {
 8233                        let inlay = Inlay::edit_prediction(
 8234                            post_inc(&mut self.next_inlay_id),
 8235                            range.start,
 8236                            new_text.as_ref(),
 8237                        );
 8238                        inlay_ids.push(inlay.id);
 8239                        inlays.push(inlay);
 8240                    }
 8241
 8242                    self.splice_inlays(&[], inlays, cx);
 8243                } else {
 8244                    let background_color = cx.theme().status().deleted_background;
 8245                    self.highlight_text::<EditPredictionHighlight>(
 8246                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8247                        HighlightStyle {
 8248                            background_color: Some(background_color),
 8249                            ..Default::default()
 8250                        },
 8251                        cx,
 8252                    );
 8253                }
 8254            }
 8255
 8256            invalidation_row_range = edit_start_row..edit_end_row;
 8257
 8258            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8259                if provider.show_tab_accept_marker() {
 8260                    EditDisplayMode::TabAccept
 8261                } else {
 8262                    EditDisplayMode::Inline
 8263                }
 8264            } else {
 8265                EditDisplayMode::DiffPopover
 8266            };
 8267
 8268            EditPrediction::Edit {
 8269                edits,
 8270                edit_preview,
 8271                display_mode,
 8272                snapshot,
 8273            }
 8274        };
 8275
 8276        let invalidation_range = multibuffer
 8277            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8278            ..multibuffer.anchor_after(Point::new(
 8279                invalidation_row_range.end,
 8280                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8281            ));
 8282
 8283        self.stale_edit_prediction_in_menu = None;
 8284        self.active_edit_prediction = Some(EditPredictionState {
 8285            inlay_ids,
 8286            completion,
 8287            completion_id,
 8288            invalidation_range: Some(invalidation_range),
 8289        });
 8290
 8291        cx.notify();
 8292
 8293        Some(())
 8294    }
 8295
 8296    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8297        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8298    }
 8299
 8300    fn clear_tasks(&mut self) {
 8301        self.tasks.clear()
 8302    }
 8303
 8304    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8305        if self.tasks.insert(key, value).is_some() {
 8306            // This case should hopefully be rare, but just in case...
 8307            log::error!(
 8308                "multiple different run targets found on a single line, only the last target will be rendered"
 8309            )
 8310        }
 8311    }
 8312
 8313    /// Get all display points of breakpoints that will be rendered within editor
 8314    ///
 8315    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8316    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8317    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8318    fn active_breakpoints(
 8319        &self,
 8320        range: Range<DisplayRow>,
 8321        window: &mut Window,
 8322        cx: &mut Context<Self>,
 8323    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8324        let mut breakpoint_display_points = HashMap::default();
 8325
 8326        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8327            return breakpoint_display_points;
 8328        };
 8329
 8330        let snapshot = self.snapshot(window, cx);
 8331
 8332        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8333        let Some(project) = self.project() else {
 8334            return breakpoint_display_points;
 8335        };
 8336
 8337        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8338            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8339
 8340        for (buffer_snapshot, range, excerpt_id) in
 8341            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8342        {
 8343            let Some(buffer) = project
 8344                .read(cx)
 8345                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8346            else {
 8347                continue;
 8348            };
 8349            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8350                &buffer,
 8351                Some(
 8352                    buffer_snapshot.anchor_before(range.start)
 8353                        ..buffer_snapshot.anchor_after(range.end),
 8354                ),
 8355                buffer_snapshot,
 8356                cx,
 8357            );
 8358            for (breakpoint, state) in breakpoints {
 8359                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8360                let position = multi_buffer_anchor
 8361                    .to_point(&multi_buffer_snapshot)
 8362                    .to_display_point(&snapshot);
 8363
 8364                breakpoint_display_points.insert(
 8365                    position.row(),
 8366                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8367                );
 8368            }
 8369        }
 8370
 8371        breakpoint_display_points
 8372    }
 8373
 8374    fn breakpoint_context_menu(
 8375        &self,
 8376        anchor: Anchor,
 8377        window: &mut Window,
 8378        cx: &mut Context<Self>,
 8379    ) -> Entity<ui::ContextMenu> {
 8380        let weak_editor = cx.weak_entity();
 8381        let focus_handle = self.focus_handle(cx);
 8382
 8383        let row = self
 8384            .buffer
 8385            .read(cx)
 8386            .snapshot(cx)
 8387            .summary_for_anchor::<Point>(&anchor)
 8388            .row;
 8389
 8390        let breakpoint = self
 8391            .breakpoint_at_row(row, window, cx)
 8392            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8393
 8394        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8395            "Edit Log Breakpoint"
 8396        } else {
 8397            "Set Log Breakpoint"
 8398        };
 8399
 8400        let condition_breakpoint_msg = if breakpoint
 8401            .as_ref()
 8402            .is_some_and(|bp| bp.1.condition.is_some())
 8403        {
 8404            "Edit Condition Breakpoint"
 8405        } else {
 8406            "Set Condition Breakpoint"
 8407        };
 8408
 8409        let hit_condition_breakpoint_msg = if breakpoint
 8410            .as_ref()
 8411            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8412        {
 8413            "Edit Hit Condition Breakpoint"
 8414        } else {
 8415            "Set Hit Condition Breakpoint"
 8416        };
 8417
 8418        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8419            "Unset Breakpoint"
 8420        } else {
 8421            "Set Breakpoint"
 8422        };
 8423
 8424        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8425
 8426        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8427            BreakpointState::Enabled => Some("Disable"),
 8428            BreakpointState::Disabled => Some("Enable"),
 8429        });
 8430
 8431        let (anchor, breakpoint) =
 8432            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8433
 8434        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8435            menu.on_blur_subscription(Subscription::new(|| {}))
 8436                .context(focus_handle)
 8437                .when(run_to_cursor, |this| {
 8438                    let weak_editor = weak_editor.clone();
 8439                    this.entry("Run to cursor", None, move |window, cx| {
 8440                        weak_editor
 8441                            .update(cx, |editor, cx| {
 8442                                editor.change_selections(
 8443                                    SelectionEffects::no_scroll(),
 8444                                    window,
 8445                                    cx,
 8446                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8447                                );
 8448                            })
 8449                            .ok();
 8450
 8451                        window.dispatch_action(Box::new(RunToCursor), cx);
 8452                    })
 8453                    .separator()
 8454                })
 8455                .when_some(toggle_state_msg, |this, msg| {
 8456                    this.entry(msg, None, {
 8457                        let weak_editor = weak_editor.clone();
 8458                        let breakpoint = breakpoint.clone();
 8459                        move |_window, cx| {
 8460                            weak_editor
 8461                                .update(cx, |this, cx| {
 8462                                    this.edit_breakpoint_at_anchor(
 8463                                        anchor,
 8464                                        breakpoint.as_ref().clone(),
 8465                                        BreakpointEditAction::InvertState,
 8466                                        cx,
 8467                                    );
 8468                                })
 8469                                .log_err();
 8470                        }
 8471                    })
 8472                })
 8473                .entry(set_breakpoint_msg, None, {
 8474                    let weak_editor = weak_editor.clone();
 8475                    let breakpoint = breakpoint.clone();
 8476                    move |_window, cx| {
 8477                        weak_editor
 8478                            .update(cx, |this, cx| {
 8479                                this.edit_breakpoint_at_anchor(
 8480                                    anchor,
 8481                                    breakpoint.as_ref().clone(),
 8482                                    BreakpointEditAction::Toggle,
 8483                                    cx,
 8484                                );
 8485                            })
 8486                            .log_err();
 8487                    }
 8488                })
 8489                .entry(log_breakpoint_msg, None, {
 8490                    let breakpoint = breakpoint.clone();
 8491                    let weak_editor = weak_editor.clone();
 8492                    move |window, cx| {
 8493                        weak_editor
 8494                            .update(cx, |this, cx| {
 8495                                this.add_edit_breakpoint_block(
 8496                                    anchor,
 8497                                    breakpoint.as_ref(),
 8498                                    BreakpointPromptEditAction::Log,
 8499                                    window,
 8500                                    cx,
 8501                                );
 8502                            })
 8503                            .log_err();
 8504                    }
 8505                })
 8506                .entry(condition_breakpoint_msg, None, {
 8507                    let breakpoint = breakpoint.clone();
 8508                    let weak_editor = weak_editor.clone();
 8509                    move |window, cx| {
 8510                        weak_editor
 8511                            .update(cx, |this, cx| {
 8512                                this.add_edit_breakpoint_block(
 8513                                    anchor,
 8514                                    breakpoint.as_ref(),
 8515                                    BreakpointPromptEditAction::Condition,
 8516                                    window,
 8517                                    cx,
 8518                                );
 8519                            })
 8520                            .log_err();
 8521                    }
 8522                })
 8523                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8524                    weak_editor
 8525                        .update(cx, |this, cx| {
 8526                            this.add_edit_breakpoint_block(
 8527                                anchor,
 8528                                breakpoint.as_ref(),
 8529                                BreakpointPromptEditAction::HitCondition,
 8530                                window,
 8531                                cx,
 8532                            );
 8533                        })
 8534                        .log_err();
 8535                })
 8536        })
 8537    }
 8538
 8539    fn render_breakpoint(
 8540        &self,
 8541        position: Anchor,
 8542        row: DisplayRow,
 8543        breakpoint: &Breakpoint,
 8544        state: Option<BreakpointSessionState>,
 8545        cx: &mut Context<Self>,
 8546    ) -> IconButton {
 8547        let is_rejected = state.is_some_and(|s| !s.verified);
 8548        // Is it a breakpoint that shows up when hovering over gutter?
 8549        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8550            (false, false),
 8551            |PhantomBreakpointIndicator {
 8552                 is_active,
 8553                 display_row,
 8554                 collides_with_existing_breakpoint,
 8555             }| {
 8556                (
 8557                    is_active && display_row == row,
 8558                    collides_with_existing_breakpoint,
 8559                )
 8560            },
 8561        );
 8562
 8563        let (color, icon) = {
 8564            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8565                (false, false) => ui::IconName::DebugBreakpoint,
 8566                (true, false) => ui::IconName::DebugLogBreakpoint,
 8567                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8568                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8569            };
 8570
 8571            let color = cx.theme().colors();
 8572
 8573            let color = if is_phantom {
 8574                if collides_with_existing {
 8575                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8576                } else {
 8577                    Color::Hint
 8578                }
 8579            } else if is_rejected {
 8580                Color::Disabled
 8581            } else {
 8582                Color::Debugger
 8583            };
 8584
 8585            (color, icon)
 8586        };
 8587
 8588        let breakpoint = Arc::from(breakpoint.clone());
 8589
 8590        let alt_as_text = gpui::Keystroke {
 8591            modifiers: Modifiers::secondary_key(),
 8592            ..Default::default()
 8593        };
 8594        let primary_action_text = if breakpoint.is_disabled() {
 8595            "Enable breakpoint"
 8596        } else if is_phantom && !collides_with_existing {
 8597            "Set breakpoint"
 8598        } else {
 8599            "Unset breakpoint"
 8600        };
 8601        let focus_handle = self.focus_handle.clone();
 8602
 8603        let meta = if is_rejected {
 8604            SharedString::from("No executable code is associated with this line.")
 8605        } else if collides_with_existing && !breakpoint.is_disabled() {
 8606            SharedString::from(format!(
 8607                "{alt_as_text}-click to disable,\nright-click for more options."
 8608            ))
 8609        } else {
 8610            SharedString::from("Right-click for more options.")
 8611        };
 8612        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8613            .icon_size(IconSize::XSmall)
 8614            .size(ui::ButtonSize::None)
 8615            .when(is_rejected, |this| {
 8616                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8617            })
 8618            .icon_color(color)
 8619            .style(ButtonStyle::Transparent)
 8620            .on_click(cx.listener({
 8621                move |editor, event: &ClickEvent, window, cx| {
 8622                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8623                        BreakpointEditAction::InvertState
 8624                    } else {
 8625                        BreakpointEditAction::Toggle
 8626                    };
 8627
 8628                    window.focus(&editor.focus_handle(cx));
 8629                    editor.edit_breakpoint_at_anchor(
 8630                        position,
 8631                        breakpoint.as_ref().clone(),
 8632                        edit_action,
 8633                        cx,
 8634                    );
 8635                }
 8636            }))
 8637            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8638                editor.set_breakpoint_context_menu(
 8639                    row,
 8640                    Some(position),
 8641                    event.position(),
 8642                    window,
 8643                    cx,
 8644                );
 8645            }))
 8646            .tooltip(move |_window, cx| {
 8647                Tooltip::with_meta_in(
 8648                    primary_action_text,
 8649                    Some(&ToggleBreakpoint),
 8650                    meta.clone(),
 8651                    &focus_handle,
 8652                    cx,
 8653                )
 8654            })
 8655    }
 8656
 8657    fn build_tasks_context(
 8658        project: &Entity<Project>,
 8659        buffer: &Entity<Buffer>,
 8660        buffer_row: u32,
 8661        tasks: &Arc<RunnableTasks>,
 8662        cx: &mut Context<Self>,
 8663    ) -> Task<Option<task::TaskContext>> {
 8664        let position = Point::new(buffer_row, tasks.column);
 8665        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8666        let location = Location {
 8667            buffer: buffer.clone(),
 8668            range: range_start..range_start,
 8669        };
 8670        // Fill in the environmental variables from the tree-sitter captures
 8671        let mut captured_task_variables = TaskVariables::default();
 8672        for (capture_name, value) in tasks.extra_variables.clone() {
 8673            captured_task_variables.insert(
 8674                task::VariableName::Custom(capture_name.into()),
 8675                value.clone(),
 8676            );
 8677        }
 8678        project.update(cx, |project, cx| {
 8679            project.task_store().update(cx, |task_store, cx| {
 8680                task_store.task_context_for_location(captured_task_variables, location, cx)
 8681            })
 8682        })
 8683    }
 8684
 8685    pub fn spawn_nearest_task(
 8686        &mut self,
 8687        action: &SpawnNearestTask,
 8688        window: &mut Window,
 8689        cx: &mut Context<Self>,
 8690    ) {
 8691        let Some((workspace, _)) = self.workspace.clone() else {
 8692            return;
 8693        };
 8694        let Some(project) = self.project.clone() else {
 8695            return;
 8696        };
 8697
 8698        // Try to find a closest, enclosing node using tree-sitter that has a task
 8699        let Some((buffer, buffer_row, tasks)) = self
 8700            .find_enclosing_node_task(cx)
 8701            // Or find the task that's closest in row-distance.
 8702            .or_else(|| self.find_closest_task(cx))
 8703        else {
 8704            return;
 8705        };
 8706
 8707        let reveal_strategy = action.reveal;
 8708        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8709        cx.spawn_in(window, async move |_, cx| {
 8710            let context = task_context.await?;
 8711            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8712
 8713            let resolved = &mut resolved_task.resolved;
 8714            resolved.reveal = reveal_strategy;
 8715
 8716            workspace
 8717                .update_in(cx, |workspace, window, cx| {
 8718                    workspace.schedule_resolved_task(
 8719                        task_source_kind,
 8720                        resolved_task,
 8721                        false,
 8722                        window,
 8723                        cx,
 8724                    );
 8725                })
 8726                .ok()
 8727        })
 8728        .detach();
 8729    }
 8730
 8731    fn find_closest_task(
 8732        &mut self,
 8733        cx: &mut Context<Self>,
 8734    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8735        let cursor_row = self
 8736            .selections
 8737            .newest_adjusted(&self.display_snapshot(cx))
 8738            .head()
 8739            .row;
 8740
 8741        let ((buffer_id, row), tasks) = self
 8742            .tasks
 8743            .iter()
 8744            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8745
 8746        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8747        let tasks = Arc::new(tasks.to_owned());
 8748        Some((buffer, *row, tasks))
 8749    }
 8750
 8751    fn find_enclosing_node_task(
 8752        &mut self,
 8753        cx: &mut Context<Self>,
 8754    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8755        let snapshot = self.buffer.read(cx).snapshot(cx);
 8756        let offset = self
 8757            .selections
 8758            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8759            .head();
 8760        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8761        let offset = excerpt.map_offset_to_buffer(offset);
 8762        let buffer_id = excerpt.buffer().remote_id();
 8763
 8764        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8765        let mut cursor = layer.node().walk();
 8766
 8767        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8768            if cursor.node().end_byte() == offset.0 {
 8769                cursor.goto_next_sibling();
 8770            }
 8771        }
 8772
 8773        // Ascend to the smallest ancestor that contains the range and has a task.
 8774        loop {
 8775            let node = cursor.node();
 8776            let node_range = node.byte_range();
 8777            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8778
 8779            // Check if this node contains our offset
 8780            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8781                // If it contains offset, check for task
 8782                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8783                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8784                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8785                }
 8786            }
 8787
 8788            if !cursor.goto_parent() {
 8789                break;
 8790            }
 8791        }
 8792        None
 8793    }
 8794
 8795    fn render_run_indicator(
 8796        &self,
 8797        _style: &EditorStyle,
 8798        is_active: bool,
 8799        row: DisplayRow,
 8800        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8801        cx: &mut Context<Self>,
 8802    ) -> IconButton {
 8803        let color = Color::Muted;
 8804        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8805
 8806        IconButton::new(
 8807            ("run_indicator", row.0 as usize),
 8808            ui::IconName::PlayOutlined,
 8809        )
 8810        .shape(ui::IconButtonShape::Square)
 8811        .icon_size(IconSize::XSmall)
 8812        .icon_color(color)
 8813        .toggle_state(is_active)
 8814        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8815            let quick_launch = match e {
 8816                ClickEvent::Keyboard(_) => true,
 8817                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8818            };
 8819
 8820            window.focus(&editor.focus_handle(cx));
 8821            editor.toggle_code_actions(
 8822                &ToggleCodeActions {
 8823                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8824                    quick_launch,
 8825                },
 8826                window,
 8827                cx,
 8828            );
 8829        }))
 8830        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8831            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8832        }))
 8833    }
 8834
 8835    pub fn context_menu_visible(&self) -> bool {
 8836        !self.edit_prediction_preview_is_active()
 8837            && self
 8838                .context_menu
 8839                .borrow()
 8840                .as_ref()
 8841                .is_some_and(|menu| menu.visible())
 8842    }
 8843
 8844    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8845        self.context_menu
 8846            .borrow()
 8847            .as_ref()
 8848            .map(|menu| menu.origin())
 8849    }
 8850
 8851    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8852        self.context_menu_options = Some(options);
 8853    }
 8854
 8855    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8856    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8857
 8858    fn render_edit_prediction_popover(
 8859        &mut self,
 8860        text_bounds: &Bounds<Pixels>,
 8861        content_origin: gpui::Point<Pixels>,
 8862        right_margin: Pixels,
 8863        editor_snapshot: &EditorSnapshot,
 8864        visible_row_range: Range<DisplayRow>,
 8865        scroll_top: ScrollOffset,
 8866        scroll_bottom: ScrollOffset,
 8867        line_layouts: &[LineWithInvisibles],
 8868        line_height: Pixels,
 8869        scroll_position: gpui::Point<ScrollOffset>,
 8870        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8871        newest_selection_head: Option<DisplayPoint>,
 8872        editor_width: Pixels,
 8873        style: &EditorStyle,
 8874        window: &mut Window,
 8875        cx: &mut App,
 8876    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8877        if self.mode().is_minimap() {
 8878            return None;
 8879        }
 8880        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8881
 8882        if self.edit_prediction_visible_in_cursor_popover(true) {
 8883            return None;
 8884        }
 8885
 8886        match &active_edit_prediction.completion {
 8887            EditPrediction::MoveWithin { target, .. } => {
 8888                let target_display_point = target.to_display_point(editor_snapshot);
 8889
 8890                if self.edit_prediction_requires_modifier() {
 8891                    if !self.edit_prediction_preview_is_active() {
 8892                        return None;
 8893                    }
 8894
 8895                    self.render_edit_prediction_modifier_jump_popover(
 8896                        text_bounds,
 8897                        content_origin,
 8898                        visible_row_range,
 8899                        line_layouts,
 8900                        line_height,
 8901                        scroll_pixel_position,
 8902                        newest_selection_head,
 8903                        target_display_point,
 8904                        window,
 8905                        cx,
 8906                    )
 8907                } else {
 8908                    self.render_edit_prediction_eager_jump_popover(
 8909                        text_bounds,
 8910                        content_origin,
 8911                        editor_snapshot,
 8912                        visible_row_range,
 8913                        scroll_top,
 8914                        scroll_bottom,
 8915                        line_height,
 8916                        scroll_pixel_position,
 8917                        target_display_point,
 8918                        editor_width,
 8919                        window,
 8920                        cx,
 8921                    )
 8922                }
 8923            }
 8924            EditPrediction::Edit {
 8925                display_mode: EditDisplayMode::Inline,
 8926                ..
 8927            } => None,
 8928            EditPrediction::Edit {
 8929                display_mode: EditDisplayMode::TabAccept,
 8930                edits,
 8931                ..
 8932            } => {
 8933                let range = &edits.first()?.0;
 8934                let target_display_point = range.end.to_display_point(editor_snapshot);
 8935
 8936                self.render_edit_prediction_end_of_line_popover(
 8937                    "Accept",
 8938                    editor_snapshot,
 8939                    visible_row_range,
 8940                    target_display_point,
 8941                    line_height,
 8942                    scroll_pixel_position,
 8943                    content_origin,
 8944                    editor_width,
 8945                    window,
 8946                    cx,
 8947                )
 8948            }
 8949            EditPrediction::Edit {
 8950                edits,
 8951                edit_preview,
 8952                display_mode: EditDisplayMode::DiffPopover,
 8953                snapshot,
 8954            } => self.render_edit_prediction_diff_popover(
 8955                text_bounds,
 8956                content_origin,
 8957                right_margin,
 8958                editor_snapshot,
 8959                visible_row_range,
 8960                line_layouts,
 8961                line_height,
 8962                scroll_position,
 8963                scroll_pixel_position,
 8964                newest_selection_head,
 8965                editor_width,
 8966                style,
 8967                edits,
 8968                edit_preview,
 8969                snapshot,
 8970                window,
 8971                cx,
 8972            ),
 8973            EditPrediction::MoveOutside { snapshot, .. } => {
 8974                let mut element = self
 8975                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8976                    .into_any();
 8977
 8978                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8979                let origin_x = text_bounds.size.width - size.width - px(30.);
 8980                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8981                element.prepaint_at(origin, window, cx);
 8982
 8983                Some((element, origin))
 8984            }
 8985        }
 8986    }
 8987
 8988    fn render_edit_prediction_modifier_jump_popover(
 8989        &mut self,
 8990        text_bounds: &Bounds<Pixels>,
 8991        content_origin: gpui::Point<Pixels>,
 8992        visible_row_range: Range<DisplayRow>,
 8993        line_layouts: &[LineWithInvisibles],
 8994        line_height: Pixels,
 8995        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8996        newest_selection_head: Option<DisplayPoint>,
 8997        target_display_point: DisplayPoint,
 8998        window: &mut Window,
 8999        cx: &mut App,
 9000    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9001        let scrolled_content_origin =
 9002            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9003
 9004        const SCROLL_PADDING_Y: Pixels = px(12.);
 9005
 9006        if target_display_point.row() < visible_row_range.start {
 9007            return self.render_edit_prediction_scroll_popover(
 9008                |_| SCROLL_PADDING_Y,
 9009                IconName::ArrowUp,
 9010                visible_row_range,
 9011                line_layouts,
 9012                newest_selection_head,
 9013                scrolled_content_origin,
 9014                window,
 9015                cx,
 9016            );
 9017        } else if target_display_point.row() >= visible_row_range.end {
 9018            return self.render_edit_prediction_scroll_popover(
 9019                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9020                IconName::ArrowDown,
 9021                visible_row_range,
 9022                line_layouts,
 9023                newest_selection_head,
 9024                scrolled_content_origin,
 9025                window,
 9026                cx,
 9027            );
 9028        }
 9029
 9030        const POLE_WIDTH: Pixels = px(2.);
 9031
 9032        let line_layout =
 9033            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9034        let target_column = target_display_point.column() as usize;
 9035
 9036        let target_x = line_layout.x_for_index(target_column);
 9037        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9038            - scroll_pixel_position.y;
 9039
 9040        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9041
 9042        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9043        border_color.l += 0.001;
 9044
 9045        let mut element = v_flex()
 9046            .items_end()
 9047            .when(flag_on_right, |el| el.items_start())
 9048            .child(if flag_on_right {
 9049                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9050                    .rounded_bl(px(0.))
 9051                    .rounded_tl(px(0.))
 9052                    .border_l_2()
 9053                    .border_color(border_color)
 9054            } else {
 9055                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9056                    .rounded_br(px(0.))
 9057                    .rounded_tr(px(0.))
 9058                    .border_r_2()
 9059                    .border_color(border_color)
 9060            })
 9061            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9062            .into_any();
 9063
 9064        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9065
 9066        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9067            - point(
 9068                if flag_on_right {
 9069                    POLE_WIDTH
 9070                } else {
 9071                    size.width - POLE_WIDTH
 9072                },
 9073                size.height - line_height,
 9074            );
 9075
 9076        origin.x = origin.x.max(content_origin.x);
 9077
 9078        element.prepaint_at(origin, window, cx);
 9079
 9080        Some((element, origin))
 9081    }
 9082
 9083    fn render_edit_prediction_scroll_popover(
 9084        &mut self,
 9085        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9086        scroll_icon: IconName,
 9087        visible_row_range: Range<DisplayRow>,
 9088        line_layouts: &[LineWithInvisibles],
 9089        newest_selection_head: Option<DisplayPoint>,
 9090        scrolled_content_origin: gpui::Point<Pixels>,
 9091        window: &mut Window,
 9092        cx: &mut App,
 9093    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9094        let mut element = self
 9095            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9096            .into_any();
 9097
 9098        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9099
 9100        let cursor = newest_selection_head?;
 9101        let cursor_row_layout =
 9102            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9103        let cursor_column = cursor.column() as usize;
 9104
 9105        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9106
 9107        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9108
 9109        element.prepaint_at(origin, window, cx);
 9110        Some((element, origin))
 9111    }
 9112
 9113    fn render_edit_prediction_eager_jump_popover(
 9114        &mut self,
 9115        text_bounds: &Bounds<Pixels>,
 9116        content_origin: gpui::Point<Pixels>,
 9117        editor_snapshot: &EditorSnapshot,
 9118        visible_row_range: Range<DisplayRow>,
 9119        scroll_top: ScrollOffset,
 9120        scroll_bottom: ScrollOffset,
 9121        line_height: Pixels,
 9122        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9123        target_display_point: DisplayPoint,
 9124        editor_width: Pixels,
 9125        window: &mut Window,
 9126        cx: &mut App,
 9127    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9128        if target_display_point.row().as_f64() < scroll_top {
 9129            let mut element = self
 9130                .render_edit_prediction_line_popover(
 9131                    "Jump to Edit",
 9132                    Some(IconName::ArrowUp),
 9133                    window,
 9134                    cx,
 9135                )
 9136                .into_any();
 9137
 9138            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9139            let offset = point(
 9140                (text_bounds.size.width - size.width) / 2.,
 9141                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9142            );
 9143
 9144            let origin = text_bounds.origin + offset;
 9145            element.prepaint_at(origin, window, cx);
 9146            Some((element, origin))
 9147        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9148            let mut element = self
 9149                .render_edit_prediction_line_popover(
 9150                    "Jump to Edit",
 9151                    Some(IconName::ArrowDown),
 9152                    window,
 9153                    cx,
 9154                )
 9155                .into_any();
 9156
 9157            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9158            let offset = point(
 9159                (text_bounds.size.width - size.width) / 2.,
 9160                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9161            );
 9162
 9163            let origin = text_bounds.origin + offset;
 9164            element.prepaint_at(origin, window, cx);
 9165            Some((element, origin))
 9166        } else {
 9167            self.render_edit_prediction_end_of_line_popover(
 9168                "Jump to Edit",
 9169                editor_snapshot,
 9170                visible_row_range,
 9171                target_display_point,
 9172                line_height,
 9173                scroll_pixel_position,
 9174                content_origin,
 9175                editor_width,
 9176                window,
 9177                cx,
 9178            )
 9179        }
 9180    }
 9181
 9182    fn render_edit_prediction_end_of_line_popover(
 9183        self: &mut Editor,
 9184        label: &'static str,
 9185        editor_snapshot: &EditorSnapshot,
 9186        visible_row_range: Range<DisplayRow>,
 9187        target_display_point: DisplayPoint,
 9188        line_height: Pixels,
 9189        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9190        content_origin: gpui::Point<Pixels>,
 9191        editor_width: Pixels,
 9192        window: &mut Window,
 9193        cx: &mut App,
 9194    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9195        let target_line_end = DisplayPoint::new(
 9196            target_display_point.row(),
 9197            editor_snapshot.line_len(target_display_point.row()),
 9198        );
 9199
 9200        let mut element = self
 9201            .render_edit_prediction_line_popover(label, None, window, cx)
 9202            .into_any();
 9203
 9204        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9205
 9206        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9207
 9208        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9209        let mut origin = start_point
 9210            + line_origin
 9211            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9212        origin.x = origin.x.max(content_origin.x);
 9213
 9214        let max_x = content_origin.x + editor_width - size.width;
 9215
 9216        if origin.x > max_x {
 9217            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9218
 9219            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9220                origin.y += offset;
 9221                IconName::ArrowUp
 9222            } else {
 9223                origin.y -= offset;
 9224                IconName::ArrowDown
 9225            };
 9226
 9227            element = self
 9228                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9229                .into_any();
 9230
 9231            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9232
 9233            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9234        }
 9235
 9236        element.prepaint_at(origin, window, cx);
 9237        Some((element, origin))
 9238    }
 9239
 9240    fn render_edit_prediction_diff_popover(
 9241        self: &Editor,
 9242        text_bounds: &Bounds<Pixels>,
 9243        content_origin: gpui::Point<Pixels>,
 9244        right_margin: Pixels,
 9245        editor_snapshot: &EditorSnapshot,
 9246        visible_row_range: Range<DisplayRow>,
 9247        line_layouts: &[LineWithInvisibles],
 9248        line_height: Pixels,
 9249        scroll_position: gpui::Point<ScrollOffset>,
 9250        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9251        newest_selection_head: Option<DisplayPoint>,
 9252        editor_width: Pixels,
 9253        style: &EditorStyle,
 9254        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9255        edit_preview: &Option<language::EditPreview>,
 9256        snapshot: &language::BufferSnapshot,
 9257        window: &mut Window,
 9258        cx: &mut App,
 9259    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9260        let edit_start = edits
 9261            .first()
 9262            .unwrap()
 9263            .0
 9264            .start
 9265            .to_display_point(editor_snapshot);
 9266        let edit_end = edits
 9267            .last()
 9268            .unwrap()
 9269            .0
 9270            .end
 9271            .to_display_point(editor_snapshot);
 9272
 9273        let is_visible = visible_row_range.contains(&edit_start.row())
 9274            || visible_row_range.contains(&edit_end.row());
 9275        if !is_visible {
 9276            return None;
 9277        }
 9278
 9279        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9280            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9281        } else {
 9282            // Fallback for providers without edit_preview
 9283            crate::edit_prediction_fallback_text(edits, cx)
 9284        };
 9285
 9286        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9287        let line_count = highlighted_edits.text.lines().count();
 9288
 9289        const BORDER_WIDTH: Pixels = px(1.);
 9290
 9291        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9292        let has_keybind = keybind.is_some();
 9293
 9294        let mut element = h_flex()
 9295            .items_start()
 9296            .child(
 9297                h_flex()
 9298                    .bg(cx.theme().colors().editor_background)
 9299                    .border(BORDER_WIDTH)
 9300                    .shadow_xs()
 9301                    .border_color(cx.theme().colors().border)
 9302                    .rounded_l_lg()
 9303                    .when(line_count > 1, |el| el.rounded_br_lg())
 9304                    .pr_1()
 9305                    .child(styled_text),
 9306            )
 9307            .child(
 9308                h_flex()
 9309                    .h(line_height + BORDER_WIDTH * 2.)
 9310                    .px_1p5()
 9311                    .gap_1()
 9312                    // Workaround: For some reason, there's a gap if we don't do this
 9313                    .ml(-BORDER_WIDTH)
 9314                    .shadow(vec![gpui::BoxShadow {
 9315                        color: gpui::black().opacity(0.05),
 9316                        offset: point(px(1.), px(1.)),
 9317                        blur_radius: px(2.),
 9318                        spread_radius: px(0.),
 9319                    }])
 9320                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9321                    .border(BORDER_WIDTH)
 9322                    .border_color(cx.theme().colors().border)
 9323                    .rounded_r_lg()
 9324                    .id("edit_prediction_diff_popover_keybind")
 9325                    .when(!has_keybind, |el| {
 9326                        let status_colors = cx.theme().status();
 9327
 9328                        el.bg(status_colors.error_background)
 9329                            .border_color(status_colors.error.opacity(0.6))
 9330                            .child(Icon::new(IconName::Info).color(Color::Error))
 9331                            .cursor_default()
 9332                            .hoverable_tooltip(move |_window, cx| {
 9333                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9334                            })
 9335                    })
 9336                    .children(keybind),
 9337            )
 9338            .into_any();
 9339
 9340        let longest_row =
 9341            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9342        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9343            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9344        } else {
 9345            layout_line(
 9346                longest_row,
 9347                editor_snapshot,
 9348                style,
 9349                editor_width,
 9350                |_| false,
 9351                window,
 9352                cx,
 9353            )
 9354            .width
 9355        };
 9356
 9357        let viewport_bounds =
 9358            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9359                right: -right_margin,
 9360                ..Default::default()
 9361            });
 9362
 9363        let x_after_longest = Pixels::from(
 9364            ScrollPixelOffset::from(
 9365                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9366            ) - scroll_pixel_position.x,
 9367        );
 9368
 9369        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9370
 9371        // Fully visible if it can be displayed within the window (allow overlapping other
 9372        // panes). However, this is only allowed if the popover starts within text_bounds.
 9373        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9374            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9375
 9376        let mut origin = if can_position_to_the_right {
 9377            point(
 9378                x_after_longest,
 9379                text_bounds.origin.y
 9380                    + Pixels::from(
 9381                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9382                            - scroll_pixel_position.y,
 9383                    ),
 9384            )
 9385        } else {
 9386            let cursor_row = newest_selection_head.map(|head| head.row());
 9387            let above_edit = edit_start
 9388                .row()
 9389                .0
 9390                .checked_sub(line_count as u32)
 9391                .map(DisplayRow);
 9392            let below_edit = Some(edit_end.row() + 1);
 9393            let above_cursor =
 9394                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9395            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9396
 9397            // Place the edit popover adjacent to the edit if there is a location
 9398            // available that is onscreen and does not obscure the cursor. Otherwise,
 9399            // place it adjacent to the cursor.
 9400            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9401                .into_iter()
 9402                .flatten()
 9403                .find(|&start_row| {
 9404                    let end_row = start_row + line_count as u32;
 9405                    visible_row_range.contains(&start_row)
 9406                        && visible_row_range.contains(&end_row)
 9407                        && cursor_row
 9408                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9409                })?;
 9410
 9411            content_origin
 9412                + point(
 9413                    Pixels::from(-scroll_pixel_position.x),
 9414                    Pixels::from(
 9415                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9416                    ),
 9417                )
 9418        };
 9419
 9420        origin.x -= BORDER_WIDTH;
 9421
 9422        window.defer_draw(element, origin, 1);
 9423
 9424        // Do not return an element, since it will already be drawn due to defer_draw.
 9425        None
 9426    }
 9427
 9428    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9429        px(30.)
 9430    }
 9431
 9432    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9433        if self.read_only(cx) {
 9434            cx.theme().players().read_only()
 9435        } else {
 9436            self.style.as_ref().unwrap().local_player
 9437        }
 9438    }
 9439
 9440    fn render_edit_prediction_accept_keybind(
 9441        &self,
 9442        window: &mut Window,
 9443        cx: &mut App,
 9444    ) -> Option<AnyElement> {
 9445        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9446        let accept_keystroke = accept_binding.keystroke()?;
 9447
 9448        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9449
 9450        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9451            Color::Accent
 9452        } else {
 9453            Color::Muted
 9454        };
 9455
 9456        h_flex()
 9457            .px_0p5()
 9458            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9459            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9460            .text_size(TextSize::XSmall.rems(cx))
 9461            .child(h_flex().children(ui::render_modifiers(
 9462                accept_keystroke.modifiers(),
 9463                PlatformStyle::platform(),
 9464                Some(modifiers_color),
 9465                Some(IconSize::XSmall.rems().into()),
 9466                true,
 9467            )))
 9468            .when(is_platform_style_mac, |parent| {
 9469                parent.child(accept_keystroke.key().to_string())
 9470            })
 9471            .when(!is_platform_style_mac, |parent| {
 9472                parent.child(
 9473                    Key::new(
 9474                        util::capitalize(accept_keystroke.key()),
 9475                        Some(Color::Default),
 9476                    )
 9477                    .size(Some(IconSize::XSmall.rems().into())),
 9478                )
 9479            })
 9480            .into_any()
 9481            .into()
 9482    }
 9483
 9484    fn render_edit_prediction_line_popover(
 9485        &self,
 9486        label: impl Into<SharedString>,
 9487        icon: Option<IconName>,
 9488        window: &mut Window,
 9489        cx: &mut App,
 9490    ) -> Stateful<Div> {
 9491        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9492
 9493        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9494        let has_keybind = keybind.is_some();
 9495
 9496        h_flex()
 9497            .id("ep-line-popover")
 9498            .py_0p5()
 9499            .pl_1()
 9500            .pr(padding_right)
 9501            .gap_1()
 9502            .rounded_md()
 9503            .border_1()
 9504            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9505            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9506            .shadow_xs()
 9507            .when(!has_keybind, |el| {
 9508                let status_colors = cx.theme().status();
 9509
 9510                el.bg(status_colors.error_background)
 9511                    .border_color(status_colors.error.opacity(0.6))
 9512                    .pl_2()
 9513                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9514                    .cursor_default()
 9515                    .hoverable_tooltip(move |_window, cx| {
 9516                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9517                    })
 9518            })
 9519            .children(keybind)
 9520            .child(
 9521                Label::new(label)
 9522                    .size(LabelSize::Small)
 9523                    .when(!has_keybind, |el| {
 9524                        el.color(cx.theme().status().error.into()).strikethrough()
 9525                    }),
 9526            )
 9527            .when(!has_keybind, |el| {
 9528                el.child(
 9529                    h_flex().ml_1().child(
 9530                        Icon::new(IconName::Info)
 9531                            .size(IconSize::Small)
 9532                            .color(cx.theme().status().error.into()),
 9533                    ),
 9534                )
 9535            })
 9536            .when_some(icon, |element, icon| {
 9537                element.child(
 9538                    div()
 9539                        .mt(px(1.5))
 9540                        .child(Icon::new(icon).size(IconSize::Small)),
 9541                )
 9542            })
 9543    }
 9544
 9545    fn render_edit_prediction_jump_outside_popover(
 9546        &self,
 9547        snapshot: &BufferSnapshot,
 9548        window: &mut Window,
 9549        cx: &mut App,
 9550    ) -> Stateful<Div> {
 9551        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9552        let has_keybind = keybind.is_some();
 9553
 9554        let file_name = snapshot
 9555            .file()
 9556            .map(|file| SharedString::new(file.file_name(cx)))
 9557            .unwrap_or(SharedString::new_static("untitled"));
 9558
 9559        h_flex()
 9560            .id("ep-jump-outside-popover")
 9561            .py_1()
 9562            .px_2()
 9563            .gap_1()
 9564            .rounded_md()
 9565            .border_1()
 9566            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9567            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9568            .shadow_xs()
 9569            .when(!has_keybind, |el| {
 9570                let status_colors = cx.theme().status();
 9571
 9572                el.bg(status_colors.error_background)
 9573                    .border_color(status_colors.error.opacity(0.6))
 9574                    .pl_2()
 9575                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9576                    .cursor_default()
 9577                    .hoverable_tooltip(move |_window, cx| {
 9578                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9579                    })
 9580            })
 9581            .children(keybind)
 9582            .child(
 9583                Label::new(file_name)
 9584                    .size(LabelSize::Small)
 9585                    .buffer_font(cx)
 9586                    .when(!has_keybind, |el| {
 9587                        el.color(cx.theme().status().error.into()).strikethrough()
 9588                    }),
 9589            )
 9590            .when(!has_keybind, |el| {
 9591                el.child(
 9592                    h_flex().ml_1().child(
 9593                        Icon::new(IconName::Info)
 9594                            .size(IconSize::Small)
 9595                            .color(cx.theme().status().error.into()),
 9596                    ),
 9597                )
 9598            })
 9599            .child(
 9600                div()
 9601                    .mt(px(1.5))
 9602                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9603            )
 9604    }
 9605
 9606    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9607        let accent_color = cx.theme().colors().text_accent;
 9608        let editor_bg_color = cx.theme().colors().editor_background;
 9609        editor_bg_color.blend(accent_color.opacity(0.1))
 9610    }
 9611
 9612    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9613        let accent_color = cx.theme().colors().text_accent;
 9614        let editor_bg_color = cx.theme().colors().editor_background;
 9615        editor_bg_color.blend(accent_color.opacity(0.6))
 9616    }
 9617    fn get_prediction_provider_icon_name(
 9618        provider: &Option<RegisteredEditPredictionDelegate>,
 9619    ) -> IconName {
 9620        match provider {
 9621            Some(provider) => match provider.provider.name() {
 9622                "copilot" => IconName::Copilot,
 9623                "supermaven" => IconName::Supermaven,
 9624                _ => IconName::ZedPredict,
 9625            },
 9626            None => IconName::ZedPredict,
 9627        }
 9628    }
 9629
 9630    fn render_edit_prediction_cursor_popover(
 9631        &self,
 9632        min_width: Pixels,
 9633        max_width: Pixels,
 9634        cursor_point: Point,
 9635        style: &EditorStyle,
 9636        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9637        _window: &Window,
 9638        cx: &mut Context<Editor>,
 9639    ) -> Option<AnyElement> {
 9640        let provider = self.edit_prediction_provider.as_ref()?;
 9641        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9642
 9643        let is_refreshing = provider.provider.is_refreshing(cx);
 9644
 9645        fn pending_completion_container(icon: IconName) -> Div {
 9646            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9647        }
 9648
 9649        let completion = match &self.active_edit_prediction {
 9650            Some(prediction) => {
 9651                if !self.has_visible_completions_menu() {
 9652                    const RADIUS: Pixels = px(6.);
 9653                    const BORDER_WIDTH: Pixels = px(1.);
 9654
 9655                    return Some(
 9656                        h_flex()
 9657                            .elevation_2(cx)
 9658                            .border(BORDER_WIDTH)
 9659                            .border_color(cx.theme().colors().border)
 9660                            .when(accept_keystroke.is_none(), |el| {
 9661                                el.border_color(cx.theme().status().error)
 9662                            })
 9663                            .rounded(RADIUS)
 9664                            .rounded_tl(px(0.))
 9665                            .overflow_hidden()
 9666                            .child(div().px_1p5().child(match &prediction.completion {
 9667                                EditPrediction::MoveWithin { target, snapshot } => {
 9668                                    use text::ToPoint as _;
 9669                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9670                                    {
 9671                                        Icon::new(IconName::ZedPredictDown)
 9672                                    } else {
 9673                                        Icon::new(IconName::ZedPredictUp)
 9674                                    }
 9675                                }
 9676                                EditPrediction::MoveOutside { .. } => {
 9677                                    // TODO [zeta2] custom icon for external jump?
 9678                                    Icon::new(provider_icon)
 9679                                }
 9680                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9681                            }))
 9682                            .child(
 9683                                h_flex()
 9684                                    .gap_1()
 9685                                    .py_1()
 9686                                    .px_2()
 9687                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9688                                    .border_l_1()
 9689                                    .border_color(cx.theme().colors().border)
 9690                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9691                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9692                                        el.child(
 9693                                            Label::new("Hold")
 9694                                                .size(LabelSize::Small)
 9695                                                .when(accept_keystroke.is_none(), |el| {
 9696                                                    el.strikethrough()
 9697                                                })
 9698                                                .line_height_style(LineHeightStyle::UiLabel),
 9699                                        )
 9700                                    })
 9701                                    .id("edit_prediction_cursor_popover_keybind")
 9702                                    .when(accept_keystroke.is_none(), |el| {
 9703                                        let status_colors = cx.theme().status();
 9704
 9705                                        el.bg(status_colors.error_background)
 9706                                            .border_color(status_colors.error.opacity(0.6))
 9707                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9708                                            .cursor_default()
 9709                                            .hoverable_tooltip(move |_window, cx| {
 9710                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9711                                                    .into()
 9712                                            })
 9713                                    })
 9714                                    .when_some(
 9715                                        accept_keystroke.as_ref(),
 9716                                        |el, accept_keystroke| {
 9717                                            el.child(h_flex().children(ui::render_modifiers(
 9718                                                accept_keystroke.modifiers(),
 9719                                                PlatformStyle::platform(),
 9720                                                Some(Color::Default),
 9721                                                Some(IconSize::XSmall.rems().into()),
 9722                                                false,
 9723                                            )))
 9724                                        },
 9725                                    ),
 9726                            )
 9727                            .into_any(),
 9728                    );
 9729                }
 9730
 9731                self.render_edit_prediction_cursor_popover_preview(
 9732                    prediction,
 9733                    cursor_point,
 9734                    style,
 9735                    cx,
 9736                )?
 9737            }
 9738
 9739            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9740                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9741                    stale_completion,
 9742                    cursor_point,
 9743                    style,
 9744                    cx,
 9745                )?,
 9746
 9747                None => pending_completion_container(provider_icon)
 9748                    .child(Label::new("...").size(LabelSize::Small)),
 9749            },
 9750
 9751            None => pending_completion_container(provider_icon)
 9752                .child(Label::new("...").size(LabelSize::Small)),
 9753        };
 9754
 9755        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9756            completion
 9757                .with_animation(
 9758                    "loading-completion",
 9759                    Animation::new(Duration::from_secs(2))
 9760                        .repeat()
 9761                        .with_easing(pulsating_between(0.4, 0.8)),
 9762                    |label, delta| label.opacity(delta),
 9763                )
 9764                .into_any_element()
 9765        } else {
 9766            completion.into_any_element()
 9767        };
 9768
 9769        let has_completion = self.active_edit_prediction.is_some();
 9770
 9771        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9772        Some(
 9773            h_flex()
 9774                .min_w(min_width)
 9775                .max_w(max_width)
 9776                .flex_1()
 9777                .elevation_2(cx)
 9778                .border_color(cx.theme().colors().border)
 9779                .child(
 9780                    div()
 9781                        .flex_1()
 9782                        .py_1()
 9783                        .px_2()
 9784                        .overflow_hidden()
 9785                        .child(completion),
 9786                )
 9787                .when_some(accept_keystroke, |el, accept_keystroke| {
 9788                    if !accept_keystroke.modifiers().modified() {
 9789                        return el;
 9790                    }
 9791
 9792                    el.child(
 9793                        h_flex()
 9794                            .h_full()
 9795                            .border_l_1()
 9796                            .rounded_r_lg()
 9797                            .border_color(cx.theme().colors().border)
 9798                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9799                            .gap_1()
 9800                            .py_1()
 9801                            .px_2()
 9802                            .child(
 9803                                h_flex()
 9804                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9805                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9806                                    .child(h_flex().children(ui::render_modifiers(
 9807                                        accept_keystroke.modifiers(),
 9808                                        PlatformStyle::platform(),
 9809                                        Some(if !has_completion {
 9810                                            Color::Muted
 9811                                        } else {
 9812                                            Color::Default
 9813                                        }),
 9814                                        None,
 9815                                        false,
 9816                                    ))),
 9817                            )
 9818                            .child(Label::new("Preview").into_any_element())
 9819                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9820                    )
 9821                })
 9822                .into_any(),
 9823        )
 9824    }
 9825
 9826    fn render_edit_prediction_cursor_popover_preview(
 9827        &self,
 9828        completion: &EditPredictionState,
 9829        cursor_point: Point,
 9830        style: &EditorStyle,
 9831        cx: &mut Context<Editor>,
 9832    ) -> Option<Div> {
 9833        use text::ToPoint as _;
 9834
 9835        fn render_relative_row_jump(
 9836            prefix: impl Into<String>,
 9837            current_row: u32,
 9838            target_row: u32,
 9839        ) -> Div {
 9840            let (row_diff, arrow) = if target_row < current_row {
 9841                (current_row - target_row, IconName::ArrowUp)
 9842            } else {
 9843                (target_row - current_row, IconName::ArrowDown)
 9844            };
 9845
 9846            h_flex()
 9847                .child(
 9848                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9849                        .color(Color::Muted)
 9850                        .size(LabelSize::Small),
 9851                )
 9852                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9853        }
 9854
 9855        let supports_jump = self
 9856            .edit_prediction_provider
 9857            .as_ref()
 9858            .map(|provider| provider.provider.supports_jump_to_edit())
 9859            .unwrap_or(true);
 9860
 9861        match &completion.completion {
 9862            EditPrediction::MoveWithin {
 9863                target, snapshot, ..
 9864            } => {
 9865                if !supports_jump {
 9866                    return None;
 9867                }
 9868
 9869                Some(
 9870                    h_flex()
 9871                        .px_2()
 9872                        .gap_2()
 9873                        .flex_1()
 9874                        .child(
 9875                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9876                                Icon::new(IconName::ZedPredictDown)
 9877                            } else {
 9878                                Icon::new(IconName::ZedPredictUp)
 9879                            },
 9880                        )
 9881                        .child(Label::new("Jump to Edit")),
 9882                )
 9883            }
 9884            EditPrediction::MoveOutside { snapshot, .. } => {
 9885                let file_name = snapshot
 9886                    .file()
 9887                    .map(|file| file.file_name(cx))
 9888                    .unwrap_or("untitled");
 9889                Some(
 9890                    h_flex()
 9891                        .px_2()
 9892                        .gap_2()
 9893                        .flex_1()
 9894                        .child(Icon::new(IconName::ZedPredict))
 9895                        .child(Label::new(format!("Jump to {file_name}"))),
 9896                )
 9897            }
 9898            EditPrediction::Edit {
 9899                edits,
 9900                edit_preview,
 9901                snapshot,
 9902                display_mode: _,
 9903            } => {
 9904                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9905
 9906                let (highlighted_edits, has_more_lines) =
 9907                    if let Some(edit_preview) = edit_preview.as_ref() {
 9908                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9909                            .first_line_preview()
 9910                    } else {
 9911                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9912                    };
 9913
 9914                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9915                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9916
 9917                let preview = h_flex()
 9918                    .gap_1()
 9919                    .min_w_16()
 9920                    .child(styled_text)
 9921                    .when(has_more_lines, |parent| parent.child(""));
 9922
 9923                let left = if supports_jump && first_edit_row != cursor_point.row {
 9924                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9925                        .into_any_element()
 9926                } else {
 9927                    let icon_name =
 9928                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9929                    Icon::new(icon_name).into_any_element()
 9930                };
 9931
 9932                Some(
 9933                    h_flex()
 9934                        .h_full()
 9935                        .flex_1()
 9936                        .gap_2()
 9937                        .pr_1()
 9938                        .overflow_x_hidden()
 9939                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9940                        .child(left)
 9941                        .child(preview),
 9942                )
 9943            }
 9944        }
 9945    }
 9946
 9947    pub fn render_context_menu(
 9948        &self,
 9949        style: &EditorStyle,
 9950        max_height_in_lines: u32,
 9951        window: &mut Window,
 9952        cx: &mut Context<Editor>,
 9953    ) -> Option<AnyElement> {
 9954        let menu = self.context_menu.borrow();
 9955        let menu = menu.as_ref()?;
 9956        if !menu.visible() {
 9957            return None;
 9958        };
 9959        Some(menu.render(style, max_height_in_lines, window, cx))
 9960    }
 9961
 9962    fn render_context_menu_aside(
 9963        &mut self,
 9964        max_size: Size<Pixels>,
 9965        window: &mut Window,
 9966        cx: &mut Context<Editor>,
 9967    ) -> Option<AnyElement> {
 9968        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9969            if menu.visible() {
 9970                menu.render_aside(max_size, window, cx)
 9971            } else {
 9972                None
 9973            }
 9974        })
 9975    }
 9976
 9977    fn hide_context_menu(
 9978        &mut self,
 9979        window: &mut Window,
 9980        cx: &mut Context<Self>,
 9981    ) -> Option<CodeContextMenu> {
 9982        cx.notify();
 9983        self.completion_tasks.clear();
 9984        let context_menu = self.context_menu.borrow_mut().take();
 9985        self.stale_edit_prediction_in_menu.take();
 9986        self.update_visible_edit_prediction(window, cx);
 9987        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9988            && let Some(completion_provider) = &self.completion_provider
 9989        {
 9990            completion_provider.selection_changed(None, window, cx);
 9991        }
 9992        context_menu
 9993    }
 9994
 9995    fn show_snippet_choices(
 9996        &mut self,
 9997        choices: &Vec<String>,
 9998        selection: Range<Anchor>,
 9999        cx: &mut Context<Self>,
10000    ) {
10001        let Some((_, buffer, _)) = self
10002            .buffer()
10003            .read(cx)
10004            .excerpt_containing(selection.start, cx)
10005        else {
10006            return;
10007        };
10008        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10009        else {
10010            return;
10011        };
10012        if buffer != end_buffer {
10013            log::error!("expected anchor range to have matching buffer IDs");
10014            return;
10015        }
10016
10017        let id = post_inc(&mut self.next_completion_id);
10018        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10019        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
10020            CompletionsMenu::new_snippet_choices(
10021                id,
10022                true,
10023                choices,
10024                selection,
10025                buffer,
10026                snippet_sort_order,
10027            ),
10028        ));
10029    }
10030
10031    pub fn insert_snippet(
10032        &mut self,
10033        insertion_ranges: &[Range<MultiBufferOffset>],
10034        snippet: Snippet,
10035        window: &mut Window,
10036        cx: &mut Context<Self>,
10037    ) -> Result<()> {
10038        struct Tabstop<T> {
10039            is_end_tabstop: bool,
10040            ranges: Vec<Range<T>>,
10041            choices: Option<Vec<String>>,
10042        }
10043
10044        let tabstops = self.buffer.update(cx, |buffer, cx| {
10045            let snippet_text: Arc<str> = snippet.text.clone().into();
10046            let edits = insertion_ranges
10047                .iter()
10048                .cloned()
10049                .map(|range| (range, snippet_text.clone()));
10050            let autoindent_mode = AutoindentMode::Block {
10051                original_indent_columns: Vec::new(),
10052            };
10053            buffer.edit(edits, Some(autoindent_mode), cx);
10054
10055            let snapshot = &*buffer.read(cx);
10056            let snippet = &snippet;
10057            snippet
10058                .tabstops
10059                .iter()
10060                .map(|tabstop| {
10061                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10062                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10063                    });
10064                    let mut tabstop_ranges = tabstop
10065                        .ranges
10066                        .iter()
10067                        .flat_map(|tabstop_range| {
10068                            let mut delta = 0_isize;
10069                            insertion_ranges.iter().map(move |insertion_range| {
10070                                let insertion_start = insertion_range.start + delta;
10071                                delta += snippet.text.len() as isize
10072                                    - (insertion_range.end - insertion_range.start) as isize;
10073
10074                                let start =
10075                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10076                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10077                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10078                            })
10079                        })
10080                        .collect::<Vec<_>>();
10081                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10082
10083                    Tabstop {
10084                        is_end_tabstop,
10085                        ranges: tabstop_ranges,
10086                        choices: tabstop.choices.clone(),
10087                    }
10088                })
10089                .collect::<Vec<_>>()
10090        });
10091        if let Some(tabstop) = tabstops.first() {
10092            self.change_selections(Default::default(), window, cx, |s| {
10093                // Reverse order so that the first range is the newest created selection.
10094                // Completions will use it and autoscroll will prioritize it.
10095                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10096            });
10097
10098            if let Some(choices) = &tabstop.choices
10099                && let Some(selection) = tabstop.ranges.first()
10100            {
10101                self.show_snippet_choices(choices, selection.clone(), cx)
10102            }
10103
10104            // If we're already at the last tabstop and it's at the end of the snippet,
10105            // we're done, we don't need to keep the state around.
10106            if !tabstop.is_end_tabstop {
10107                let choices = tabstops
10108                    .iter()
10109                    .map(|tabstop| tabstop.choices.clone())
10110                    .collect();
10111
10112                let ranges = tabstops
10113                    .into_iter()
10114                    .map(|tabstop| tabstop.ranges)
10115                    .collect::<Vec<_>>();
10116
10117                self.snippet_stack.push(SnippetState {
10118                    active_index: 0,
10119                    ranges,
10120                    choices,
10121                });
10122            }
10123
10124            // Check whether the just-entered snippet ends with an auto-closable bracket.
10125            if self.autoclose_regions.is_empty() {
10126                let snapshot = self.buffer.read(cx).snapshot(cx);
10127                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10128                    let selection_head = selection.head();
10129                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10130                        continue;
10131                    };
10132
10133                    let mut bracket_pair = None;
10134                    let max_lookup_length = scope
10135                        .brackets()
10136                        .map(|(pair, _)| {
10137                            pair.start
10138                                .as_str()
10139                                .chars()
10140                                .count()
10141                                .max(pair.end.as_str().chars().count())
10142                        })
10143                        .max();
10144                    if let Some(max_lookup_length) = max_lookup_length {
10145                        let next_text = snapshot
10146                            .chars_at(selection_head)
10147                            .take(max_lookup_length)
10148                            .collect::<String>();
10149                        let prev_text = snapshot
10150                            .reversed_chars_at(selection_head)
10151                            .take(max_lookup_length)
10152                            .collect::<String>();
10153
10154                        for (pair, enabled) in scope.brackets() {
10155                            if enabled
10156                                && pair.close
10157                                && prev_text.starts_with(pair.start.as_str())
10158                                && next_text.starts_with(pair.end.as_str())
10159                            {
10160                                bracket_pair = Some(pair.clone());
10161                                break;
10162                            }
10163                        }
10164                    }
10165
10166                    if let Some(pair) = bracket_pair {
10167                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10168                        let autoclose_enabled =
10169                            self.use_autoclose && snapshot_settings.use_autoclose;
10170                        if autoclose_enabled {
10171                            let start = snapshot.anchor_after(selection_head);
10172                            let end = snapshot.anchor_after(selection_head);
10173                            self.autoclose_regions.push(AutocloseRegion {
10174                                selection_id: selection.id,
10175                                range: start..end,
10176                                pair,
10177                            });
10178                        }
10179                    }
10180                }
10181            }
10182        }
10183        Ok(())
10184    }
10185
10186    pub fn move_to_next_snippet_tabstop(
10187        &mut self,
10188        window: &mut Window,
10189        cx: &mut Context<Self>,
10190    ) -> bool {
10191        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10192    }
10193
10194    pub fn move_to_prev_snippet_tabstop(
10195        &mut self,
10196        window: &mut Window,
10197        cx: &mut Context<Self>,
10198    ) -> bool {
10199        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10200    }
10201
10202    pub fn move_to_snippet_tabstop(
10203        &mut self,
10204        bias: Bias,
10205        window: &mut Window,
10206        cx: &mut Context<Self>,
10207    ) -> bool {
10208        if let Some(mut snippet) = self.snippet_stack.pop() {
10209            match bias {
10210                Bias::Left => {
10211                    if snippet.active_index > 0 {
10212                        snippet.active_index -= 1;
10213                    } else {
10214                        self.snippet_stack.push(snippet);
10215                        return false;
10216                    }
10217                }
10218                Bias::Right => {
10219                    if snippet.active_index + 1 < snippet.ranges.len() {
10220                        snippet.active_index += 1;
10221                    } else {
10222                        self.snippet_stack.push(snippet);
10223                        return false;
10224                    }
10225                }
10226            }
10227            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10228                self.change_selections(Default::default(), window, cx, |s| {
10229                    // Reverse order so that the first range is the newest created selection.
10230                    // Completions will use it and autoscroll will prioritize it.
10231                    s.select_ranges(current_ranges.iter().rev().cloned())
10232                });
10233
10234                if let Some(choices) = &snippet.choices[snippet.active_index]
10235                    && let Some(selection) = current_ranges.first()
10236                {
10237                    self.show_snippet_choices(choices, selection.clone(), cx);
10238                }
10239
10240                // If snippet state is not at the last tabstop, push it back on the stack
10241                if snippet.active_index + 1 < snippet.ranges.len() {
10242                    self.snippet_stack.push(snippet);
10243                }
10244                return true;
10245            }
10246        }
10247
10248        false
10249    }
10250
10251    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10252        self.transact(window, cx, |this, window, cx| {
10253            this.select_all(&SelectAll, window, cx);
10254            this.insert("", window, cx);
10255        });
10256    }
10257
10258    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10259        if self.read_only(cx) {
10260            return;
10261        }
10262        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10263        self.transact(window, cx, |this, window, cx| {
10264            this.select_autoclose_pair(window, cx);
10265
10266            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10267
10268            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10269            if !this.linked_edit_ranges.is_empty() {
10270                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10271                let snapshot = this.buffer.read(cx).snapshot(cx);
10272
10273                for selection in selections.iter() {
10274                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10275                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10276                    if selection_start.buffer_id != selection_end.buffer_id {
10277                        continue;
10278                    }
10279                    if let Some(ranges) =
10280                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10281                    {
10282                        for (buffer, entries) in ranges {
10283                            linked_ranges.entry(buffer).or_default().extend(entries);
10284                        }
10285                    }
10286                }
10287            }
10288
10289            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10290            for selection in &mut selections {
10291                if selection.is_empty() {
10292                    let old_head = selection.head();
10293                    let mut new_head =
10294                        movement::left(&display_map, old_head.to_display_point(&display_map))
10295                            .to_point(&display_map);
10296                    if let Some((buffer, line_buffer_range)) = display_map
10297                        .buffer_snapshot()
10298                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10299                    {
10300                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10301                        let indent_len = match indent_size.kind {
10302                            IndentKind::Space => {
10303                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10304                            }
10305                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10306                        };
10307                        if old_head.column <= indent_size.len && old_head.column > 0 {
10308                            let indent_len = indent_len.get();
10309                            new_head = cmp::min(
10310                                new_head,
10311                                MultiBufferPoint::new(
10312                                    old_head.row,
10313                                    ((old_head.column - 1) / indent_len) * indent_len,
10314                                ),
10315                            );
10316                        }
10317                    }
10318
10319                    selection.set_head(new_head, SelectionGoal::None);
10320                }
10321            }
10322
10323            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10324            this.insert("", window, cx);
10325            let empty_str: Arc<str> = Arc::from("");
10326            for (buffer, edits) in linked_ranges {
10327                let snapshot = buffer.read(cx).snapshot();
10328                use text::ToPoint as TP;
10329
10330                let edits = edits
10331                    .into_iter()
10332                    .map(|range| {
10333                        let end_point = TP::to_point(&range.end, &snapshot);
10334                        let mut start_point = TP::to_point(&range.start, &snapshot);
10335
10336                        if end_point == start_point {
10337                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10338                                .saturating_sub(1);
10339                            start_point =
10340                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10341                        };
10342
10343                        (start_point..end_point, empty_str.clone())
10344                    })
10345                    .sorted_by_key(|(range, _)| range.start)
10346                    .collect::<Vec<_>>();
10347                buffer.update(cx, |this, cx| {
10348                    this.edit(edits, None, cx);
10349                })
10350            }
10351            this.refresh_edit_prediction(true, false, window, cx);
10352            refresh_linked_ranges(this, window, cx);
10353        });
10354    }
10355
10356    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10357        if self.read_only(cx) {
10358            return;
10359        }
10360        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10361        self.transact(window, cx, |this, window, cx| {
10362            this.change_selections(Default::default(), window, cx, |s| {
10363                s.move_with(|map, selection| {
10364                    if selection.is_empty() {
10365                        let cursor = movement::right(map, selection.head());
10366                        selection.end = cursor;
10367                        selection.reversed = true;
10368                        selection.goal = SelectionGoal::None;
10369                    }
10370                })
10371            });
10372            this.insert("", window, cx);
10373            this.refresh_edit_prediction(true, false, window, cx);
10374        });
10375    }
10376
10377    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10378        if self.mode.is_single_line() {
10379            cx.propagate();
10380            return;
10381        }
10382
10383        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10384        if self.move_to_prev_snippet_tabstop(window, cx) {
10385            return;
10386        }
10387        self.outdent(&Outdent, window, cx);
10388    }
10389
10390    pub fn next_snippet_tabstop(
10391        &mut self,
10392        _: &NextSnippetTabstop,
10393        window: &mut Window,
10394        cx: &mut Context<Self>,
10395    ) {
10396        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10397            cx.propagate();
10398            return;
10399        }
10400
10401        if self.move_to_next_snippet_tabstop(window, cx) {
10402            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10403            return;
10404        }
10405        cx.propagate();
10406    }
10407
10408    pub fn previous_snippet_tabstop(
10409        &mut self,
10410        _: &PreviousSnippetTabstop,
10411        window: &mut Window,
10412        cx: &mut Context<Self>,
10413    ) {
10414        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10415            cx.propagate();
10416            return;
10417        }
10418
10419        if self.move_to_prev_snippet_tabstop(window, cx) {
10420            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10421            return;
10422        }
10423        cx.propagate();
10424    }
10425
10426    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10427        if self.mode.is_single_line() {
10428            cx.propagate();
10429            return;
10430        }
10431
10432        if self.move_to_next_snippet_tabstop(window, cx) {
10433            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10434            return;
10435        }
10436        if self.read_only(cx) {
10437            return;
10438        }
10439        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10440        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10441        let buffer = self.buffer.read(cx);
10442        let snapshot = buffer.snapshot(cx);
10443        let rows_iter = selections.iter().map(|s| s.head().row);
10444        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10445
10446        let has_some_cursor_in_whitespace = selections
10447            .iter()
10448            .filter(|selection| selection.is_empty())
10449            .any(|selection| {
10450                let cursor = selection.head();
10451                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10452                cursor.column < current_indent.len
10453            });
10454
10455        let mut edits = Vec::new();
10456        let mut prev_edited_row = 0;
10457        let mut row_delta = 0;
10458        for selection in &mut selections {
10459            if selection.start.row != prev_edited_row {
10460                row_delta = 0;
10461            }
10462            prev_edited_row = selection.end.row;
10463
10464            // If the selection is non-empty, then increase the indentation of the selected lines.
10465            if !selection.is_empty() {
10466                row_delta =
10467                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10468                continue;
10469            }
10470
10471            let cursor = selection.head();
10472            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10473            if let Some(suggested_indent) =
10474                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10475            {
10476                // Don't do anything if already at suggested indent
10477                // and there is any other cursor which is not
10478                if has_some_cursor_in_whitespace
10479                    && cursor.column == current_indent.len
10480                    && current_indent.len == suggested_indent.len
10481                {
10482                    continue;
10483                }
10484
10485                // Adjust line and move cursor to suggested indent
10486                // if cursor is not at suggested indent
10487                if cursor.column < suggested_indent.len
10488                    && cursor.column <= current_indent.len
10489                    && current_indent.len <= suggested_indent.len
10490                {
10491                    selection.start = Point::new(cursor.row, suggested_indent.len);
10492                    selection.end = selection.start;
10493                    if row_delta == 0 {
10494                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10495                            cursor.row,
10496                            current_indent,
10497                            suggested_indent,
10498                        ));
10499                        row_delta = suggested_indent.len - current_indent.len;
10500                    }
10501                    continue;
10502                }
10503
10504                // If current indent is more than suggested indent
10505                // only move cursor to current indent and skip indent
10506                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10507                    selection.start = Point::new(cursor.row, current_indent.len);
10508                    selection.end = selection.start;
10509                    continue;
10510                }
10511            }
10512
10513            // Otherwise, insert a hard or soft tab.
10514            let settings = buffer.language_settings_at(cursor, cx);
10515            let tab_size = if settings.hard_tabs {
10516                IndentSize::tab()
10517            } else {
10518                let tab_size = settings.tab_size.get();
10519                let indent_remainder = snapshot
10520                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10521                    .flat_map(str::chars)
10522                    .fold(row_delta % tab_size, |counter: u32, c| {
10523                        if c == '\t' {
10524                            0
10525                        } else {
10526                            (counter + 1) % tab_size
10527                        }
10528                    });
10529
10530                let chars_to_next_tab_stop = tab_size - indent_remainder;
10531                IndentSize::spaces(chars_to_next_tab_stop)
10532            };
10533            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10534            selection.end = selection.start;
10535            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10536            row_delta += tab_size.len;
10537        }
10538
10539        self.transact(window, cx, |this, window, cx| {
10540            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10541            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10542            this.refresh_edit_prediction(true, false, window, cx);
10543        });
10544    }
10545
10546    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10547        if self.read_only(cx) {
10548            return;
10549        }
10550        if self.mode.is_single_line() {
10551            cx.propagate();
10552            return;
10553        }
10554
10555        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10556        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10557        let mut prev_edited_row = 0;
10558        let mut row_delta = 0;
10559        let mut edits = Vec::new();
10560        let buffer = self.buffer.read(cx);
10561        let snapshot = buffer.snapshot(cx);
10562        for selection in &mut selections {
10563            if selection.start.row != prev_edited_row {
10564                row_delta = 0;
10565            }
10566            prev_edited_row = selection.end.row;
10567
10568            row_delta =
10569                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10570        }
10571
10572        self.transact(window, cx, |this, window, cx| {
10573            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10574            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10575        });
10576    }
10577
10578    fn indent_selection(
10579        buffer: &MultiBuffer,
10580        snapshot: &MultiBufferSnapshot,
10581        selection: &mut Selection<Point>,
10582        edits: &mut Vec<(Range<Point>, String)>,
10583        delta_for_start_row: u32,
10584        cx: &App,
10585    ) -> u32 {
10586        let settings = buffer.language_settings_at(selection.start, cx);
10587        let tab_size = settings.tab_size.get();
10588        let indent_kind = if settings.hard_tabs {
10589            IndentKind::Tab
10590        } else {
10591            IndentKind::Space
10592        };
10593        let mut start_row = selection.start.row;
10594        let mut end_row = selection.end.row + 1;
10595
10596        // If a selection ends at the beginning of a line, don't indent
10597        // that last line.
10598        if selection.end.column == 0 && selection.end.row > selection.start.row {
10599            end_row -= 1;
10600        }
10601
10602        // Avoid re-indenting a row that has already been indented by a
10603        // previous selection, but still update this selection's column
10604        // to reflect that indentation.
10605        if delta_for_start_row > 0 {
10606            start_row += 1;
10607            selection.start.column += delta_for_start_row;
10608            if selection.end.row == selection.start.row {
10609                selection.end.column += delta_for_start_row;
10610            }
10611        }
10612
10613        let mut delta_for_end_row = 0;
10614        let has_multiple_rows = start_row + 1 != end_row;
10615        for row in start_row..end_row {
10616            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10617            let indent_delta = match (current_indent.kind, indent_kind) {
10618                (IndentKind::Space, IndentKind::Space) => {
10619                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10620                    IndentSize::spaces(columns_to_next_tab_stop)
10621                }
10622                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10623                (_, IndentKind::Tab) => IndentSize::tab(),
10624            };
10625
10626            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10627                0
10628            } else {
10629                selection.start.column
10630            };
10631            let row_start = Point::new(row, start);
10632            edits.push((
10633                row_start..row_start,
10634                indent_delta.chars().collect::<String>(),
10635            ));
10636
10637            // Update this selection's endpoints to reflect the indentation.
10638            if row == selection.start.row {
10639                selection.start.column += indent_delta.len;
10640            }
10641            if row == selection.end.row {
10642                selection.end.column += indent_delta.len;
10643                delta_for_end_row = indent_delta.len;
10644            }
10645        }
10646
10647        if selection.start.row == selection.end.row {
10648            delta_for_start_row + delta_for_end_row
10649        } else {
10650            delta_for_end_row
10651        }
10652    }
10653
10654    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10655        if self.read_only(cx) {
10656            return;
10657        }
10658        if self.mode.is_single_line() {
10659            cx.propagate();
10660            return;
10661        }
10662
10663        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10664        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10665        let selections = self.selections.all::<Point>(&display_map);
10666        let mut deletion_ranges = Vec::new();
10667        let mut last_outdent = None;
10668        {
10669            let buffer = self.buffer.read(cx);
10670            let snapshot = buffer.snapshot(cx);
10671            for selection in &selections {
10672                let settings = buffer.language_settings_at(selection.start, cx);
10673                let tab_size = settings.tab_size.get();
10674                let mut rows = selection.spanned_rows(false, &display_map);
10675
10676                // Avoid re-outdenting a row that has already been outdented by a
10677                // previous selection.
10678                if let Some(last_row) = last_outdent
10679                    && last_row == rows.start
10680                {
10681                    rows.start = rows.start.next_row();
10682                }
10683                let has_multiple_rows = rows.len() > 1;
10684                for row in rows.iter_rows() {
10685                    let indent_size = snapshot.indent_size_for_line(row);
10686                    if indent_size.len > 0 {
10687                        let deletion_len = match indent_size.kind {
10688                            IndentKind::Space => {
10689                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10690                                if columns_to_prev_tab_stop == 0 {
10691                                    tab_size
10692                                } else {
10693                                    columns_to_prev_tab_stop
10694                                }
10695                            }
10696                            IndentKind::Tab => 1,
10697                        };
10698                        let start = if has_multiple_rows
10699                            || deletion_len > selection.start.column
10700                            || indent_size.len < selection.start.column
10701                        {
10702                            0
10703                        } else {
10704                            selection.start.column - deletion_len
10705                        };
10706                        deletion_ranges.push(
10707                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10708                        );
10709                        last_outdent = Some(row);
10710                    }
10711                }
10712            }
10713        }
10714
10715        self.transact(window, cx, |this, window, cx| {
10716            this.buffer.update(cx, |buffer, cx| {
10717                let empty_str: Arc<str> = Arc::default();
10718                buffer.edit(
10719                    deletion_ranges
10720                        .into_iter()
10721                        .map(|range| (range, empty_str.clone())),
10722                    None,
10723                    cx,
10724                );
10725            });
10726            let selections = this
10727                .selections
10728                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10729            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10730        });
10731    }
10732
10733    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10734        if self.read_only(cx) {
10735            return;
10736        }
10737        if self.mode.is_single_line() {
10738            cx.propagate();
10739            return;
10740        }
10741
10742        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10743        let selections = self
10744            .selections
10745            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10746            .into_iter()
10747            .map(|s| s.range());
10748
10749        self.transact(window, cx, |this, window, cx| {
10750            this.buffer.update(cx, |buffer, cx| {
10751                buffer.autoindent_ranges(selections, cx);
10752            });
10753            let selections = this
10754                .selections
10755                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10756            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10757        });
10758    }
10759
10760    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10761        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10762        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10763        let selections = self.selections.all::<Point>(&display_map);
10764
10765        let mut new_cursors = Vec::new();
10766        let mut edit_ranges = Vec::new();
10767        let mut selections = selections.iter().peekable();
10768        while let Some(selection) = selections.next() {
10769            let mut rows = selection.spanned_rows(false, &display_map);
10770
10771            // Accumulate contiguous regions of rows that we want to delete.
10772            while let Some(next_selection) = selections.peek() {
10773                let next_rows = next_selection.spanned_rows(false, &display_map);
10774                if next_rows.start <= rows.end {
10775                    rows.end = next_rows.end;
10776                    selections.next().unwrap();
10777                } else {
10778                    break;
10779                }
10780            }
10781
10782            let buffer = display_map.buffer_snapshot();
10783            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10784            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10785                // If there's a line after the range, delete the \n from the end of the row range
10786                (
10787                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10788                    rows.end,
10789                )
10790            } else {
10791                // If there isn't a line after the range, delete the \n from the line before the
10792                // start of the row range
10793                edit_start = edit_start.saturating_sub_usize(1);
10794                (buffer.len(), rows.start.previous_row())
10795            };
10796
10797            let text_layout_details = self.text_layout_details(window);
10798            let x = display_map.x_for_display_point(
10799                selection.head().to_display_point(&display_map),
10800                &text_layout_details,
10801            );
10802            let row = Point::new(target_row.0, 0)
10803                .to_display_point(&display_map)
10804                .row();
10805            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10806
10807            new_cursors.push((
10808                selection.id,
10809                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10810                SelectionGoal::None,
10811            ));
10812            edit_ranges.push(edit_start..edit_end);
10813        }
10814
10815        self.transact(window, cx, |this, window, cx| {
10816            let buffer = this.buffer.update(cx, |buffer, cx| {
10817                let empty_str: Arc<str> = Arc::default();
10818                buffer.edit(
10819                    edit_ranges
10820                        .into_iter()
10821                        .map(|range| (range, empty_str.clone())),
10822                    None,
10823                    cx,
10824                );
10825                buffer.snapshot(cx)
10826            });
10827            let new_selections = new_cursors
10828                .into_iter()
10829                .map(|(id, cursor, goal)| {
10830                    let cursor = cursor.to_point(&buffer);
10831                    Selection {
10832                        id,
10833                        start: cursor,
10834                        end: cursor,
10835                        reversed: false,
10836                        goal,
10837                    }
10838                })
10839                .collect();
10840
10841            this.change_selections(Default::default(), window, cx, |s| {
10842                s.select(new_selections);
10843            });
10844        });
10845    }
10846
10847    pub fn join_lines_impl(
10848        &mut self,
10849        insert_whitespace: bool,
10850        window: &mut Window,
10851        cx: &mut Context<Self>,
10852    ) {
10853        if self.read_only(cx) {
10854            return;
10855        }
10856        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10857        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10858            let start = MultiBufferRow(selection.start.row);
10859            // Treat single line selections as if they include the next line. Otherwise this action
10860            // would do nothing for single line selections individual cursors.
10861            let end = if selection.start.row == selection.end.row {
10862                MultiBufferRow(selection.start.row + 1)
10863            } else {
10864                MultiBufferRow(selection.end.row)
10865            };
10866
10867            if let Some(last_row_range) = row_ranges.last_mut()
10868                && start <= last_row_range.end
10869            {
10870                last_row_range.end = end;
10871                continue;
10872            }
10873            row_ranges.push(start..end);
10874        }
10875
10876        let snapshot = self.buffer.read(cx).snapshot(cx);
10877        let mut cursor_positions = Vec::new();
10878        for row_range in &row_ranges {
10879            let anchor = snapshot.anchor_before(Point::new(
10880                row_range.end.previous_row().0,
10881                snapshot.line_len(row_range.end.previous_row()),
10882            ));
10883            cursor_positions.push(anchor..anchor);
10884        }
10885
10886        self.transact(window, cx, |this, window, cx| {
10887            for row_range in row_ranges.into_iter().rev() {
10888                for row in row_range.iter_rows().rev() {
10889                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10890                    let next_line_row = row.next_row();
10891                    let indent = snapshot.indent_size_for_line(next_line_row);
10892                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10893
10894                    let replace =
10895                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10896                            " "
10897                        } else {
10898                            ""
10899                        };
10900
10901                    this.buffer.update(cx, |buffer, cx| {
10902                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10903                    });
10904                }
10905            }
10906
10907            this.change_selections(Default::default(), window, cx, |s| {
10908                s.select_anchor_ranges(cursor_positions)
10909            });
10910        });
10911    }
10912
10913    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10914        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10915        self.join_lines_impl(true, window, cx);
10916    }
10917
10918    pub fn sort_lines_case_sensitive(
10919        &mut self,
10920        _: &SortLinesCaseSensitive,
10921        window: &mut Window,
10922        cx: &mut Context<Self>,
10923    ) {
10924        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10925    }
10926
10927    pub fn sort_lines_by_length(
10928        &mut self,
10929        _: &SortLinesByLength,
10930        window: &mut Window,
10931        cx: &mut Context<Self>,
10932    ) {
10933        self.manipulate_immutable_lines(window, cx, |lines| {
10934            lines.sort_by_key(|&line| line.chars().count())
10935        })
10936    }
10937
10938    pub fn sort_lines_case_insensitive(
10939        &mut self,
10940        _: &SortLinesCaseInsensitive,
10941        window: &mut Window,
10942        cx: &mut Context<Self>,
10943    ) {
10944        self.manipulate_immutable_lines(window, cx, |lines| {
10945            lines.sort_by_key(|line| line.to_lowercase())
10946        })
10947    }
10948
10949    pub fn unique_lines_case_insensitive(
10950        &mut self,
10951        _: &UniqueLinesCaseInsensitive,
10952        window: &mut Window,
10953        cx: &mut Context<Self>,
10954    ) {
10955        self.manipulate_immutable_lines(window, cx, |lines| {
10956            let mut seen = HashSet::default();
10957            lines.retain(|line| seen.insert(line.to_lowercase()));
10958        })
10959    }
10960
10961    pub fn unique_lines_case_sensitive(
10962        &mut self,
10963        _: &UniqueLinesCaseSensitive,
10964        window: &mut Window,
10965        cx: &mut Context<Self>,
10966    ) {
10967        self.manipulate_immutable_lines(window, cx, |lines| {
10968            let mut seen = HashSet::default();
10969            lines.retain(|line| seen.insert(*line));
10970        })
10971    }
10972
10973    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10974        let snapshot = self.buffer.read(cx).snapshot(cx);
10975        for selection in self.selections.disjoint_anchors_arc().iter() {
10976            if snapshot
10977                .language_at(selection.start)
10978                .and_then(|lang| lang.config().wrap_characters.as_ref())
10979                .is_some()
10980            {
10981                return true;
10982            }
10983        }
10984        false
10985    }
10986
10987    fn wrap_selections_in_tag(
10988        &mut self,
10989        _: &WrapSelectionsInTag,
10990        window: &mut Window,
10991        cx: &mut Context<Self>,
10992    ) {
10993        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10994
10995        let snapshot = self.buffer.read(cx).snapshot(cx);
10996
10997        let mut edits = Vec::new();
10998        let mut boundaries = Vec::new();
10999
11000        for selection in self
11001            .selections
11002            .all_adjusted(&self.display_snapshot(cx))
11003            .iter()
11004        {
11005            let Some(wrap_config) = snapshot
11006                .language_at(selection.start)
11007                .and_then(|lang| lang.config().wrap_characters.clone())
11008            else {
11009                continue;
11010            };
11011
11012            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11013            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11014
11015            let start_before = snapshot.anchor_before(selection.start);
11016            let end_after = snapshot.anchor_after(selection.end);
11017
11018            edits.push((start_before..start_before, open_tag));
11019            edits.push((end_after..end_after, close_tag));
11020
11021            boundaries.push((
11022                start_before,
11023                end_after,
11024                wrap_config.start_prefix.len(),
11025                wrap_config.end_suffix.len(),
11026            ));
11027        }
11028
11029        if edits.is_empty() {
11030            return;
11031        }
11032
11033        self.transact(window, cx, |this, window, cx| {
11034            let buffer = this.buffer.update(cx, |buffer, cx| {
11035                buffer.edit(edits, None, cx);
11036                buffer.snapshot(cx)
11037            });
11038
11039            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11040            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11041                boundaries.into_iter()
11042            {
11043                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11044                let close_offset = end_after
11045                    .to_offset(&buffer)
11046                    .saturating_sub_usize(end_suffix_len);
11047                new_selections.push(open_offset..open_offset);
11048                new_selections.push(close_offset..close_offset);
11049            }
11050
11051            this.change_selections(Default::default(), window, cx, |s| {
11052                s.select_ranges(new_selections);
11053            });
11054
11055            this.request_autoscroll(Autoscroll::fit(), cx);
11056        });
11057    }
11058
11059    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11060        let Some(project) = self.project.clone() else {
11061            return;
11062        };
11063        self.reload(project, window, cx)
11064            .detach_and_notify_err(window, cx);
11065    }
11066
11067    pub fn restore_file(
11068        &mut self,
11069        _: &::git::RestoreFile,
11070        window: &mut Window,
11071        cx: &mut Context<Self>,
11072    ) {
11073        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11074        let mut buffer_ids = HashSet::default();
11075        let snapshot = self.buffer().read(cx).snapshot(cx);
11076        for selection in self
11077            .selections
11078            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11079        {
11080            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11081        }
11082
11083        let buffer = self.buffer().read(cx);
11084        let ranges = buffer_ids
11085            .into_iter()
11086            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11087            .collect::<Vec<_>>();
11088
11089        self.restore_hunks_in_ranges(ranges, window, cx);
11090    }
11091
11092    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11093        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11094        let selections = self
11095            .selections
11096            .all(&self.display_snapshot(cx))
11097            .into_iter()
11098            .map(|s| s.range())
11099            .collect();
11100        self.restore_hunks_in_ranges(selections, window, cx);
11101    }
11102
11103    pub fn restore_hunks_in_ranges(
11104        &mut self,
11105        ranges: Vec<Range<Point>>,
11106        window: &mut Window,
11107        cx: &mut Context<Editor>,
11108    ) {
11109        let mut revert_changes = HashMap::default();
11110        let chunk_by = self
11111            .snapshot(window, cx)
11112            .hunks_for_ranges(ranges)
11113            .into_iter()
11114            .chunk_by(|hunk| hunk.buffer_id);
11115        for (buffer_id, hunks) in &chunk_by {
11116            let hunks = hunks.collect::<Vec<_>>();
11117            for hunk in &hunks {
11118                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11119            }
11120            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11121        }
11122        drop(chunk_by);
11123        if !revert_changes.is_empty() {
11124            self.transact(window, cx, |editor, window, cx| {
11125                editor.restore(revert_changes, window, cx);
11126            });
11127        }
11128    }
11129
11130    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11131        if let Some(status) = self
11132            .addons
11133            .iter()
11134            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11135        {
11136            return Some(status);
11137        }
11138        self.project
11139            .as_ref()?
11140            .read(cx)
11141            .status_for_buffer_id(buffer_id, cx)
11142    }
11143
11144    pub fn open_active_item_in_terminal(
11145        &mut self,
11146        _: &OpenInTerminal,
11147        window: &mut Window,
11148        cx: &mut Context<Self>,
11149    ) {
11150        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11151            let project_path = buffer.read(cx).project_path(cx)?;
11152            let project = self.project()?.read(cx);
11153            let entry = project.entry_for_path(&project_path, cx)?;
11154            let parent = match &entry.canonical_path {
11155                Some(canonical_path) => canonical_path.to_path_buf(),
11156                None => project.absolute_path(&project_path, cx)?,
11157            }
11158            .parent()?
11159            .to_path_buf();
11160            Some(parent)
11161        }) {
11162            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11163        }
11164    }
11165
11166    fn set_breakpoint_context_menu(
11167        &mut self,
11168        display_row: DisplayRow,
11169        position: Option<Anchor>,
11170        clicked_point: gpui::Point<Pixels>,
11171        window: &mut Window,
11172        cx: &mut Context<Self>,
11173    ) {
11174        let source = self
11175            .buffer
11176            .read(cx)
11177            .snapshot(cx)
11178            .anchor_before(Point::new(display_row.0, 0u32));
11179
11180        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11181
11182        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11183            self,
11184            source,
11185            clicked_point,
11186            context_menu,
11187            window,
11188            cx,
11189        );
11190    }
11191
11192    fn add_edit_breakpoint_block(
11193        &mut self,
11194        anchor: Anchor,
11195        breakpoint: &Breakpoint,
11196        edit_action: BreakpointPromptEditAction,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199    ) {
11200        let weak_editor = cx.weak_entity();
11201        let bp_prompt = cx.new(|cx| {
11202            BreakpointPromptEditor::new(
11203                weak_editor,
11204                anchor,
11205                breakpoint.clone(),
11206                edit_action,
11207                window,
11208                cx,
11209            )
11210        });
11211
11212        let height = bp_prompt.update(cx, |this, cx| {
11213            this.prompt
11214                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11215        });
11216        let cloned_prompt = bp_prompt.clone();
11217        let blocks = vec![BlockProperties {
11218            style: BlockStyle::Sticky,
11219            placement: BlockPlacement::Above(anchor),
11220            height: Some(height),
11221            render: Arc::new(move |cx| {
11222                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11223                cloned_prompt.clone().into_any_element()
11224            }),
11225            priority: 0,
11226        }];
11227
11228        let focus_handle = bp_prompt.focus_handle(cx);
11229        window.focus(&focus_handle);
11230
11231        let block_ids = self.insert_blocks(blocks, None, cx);
11232        bp_prompt.update(cx, |prompt, _| {
11233            prompt.add_block_ids(block_ids);
11234        });
11235    }
11236
11237    pub(crate) fn breakpoint_at_row(
11238        &self,
11239        row: u32,
11240        window: &mut Window,
11241        cx: &mut Context<Self>,
11242    ) -> Option<(Anchor, Breakpoint)> {
11243        let snapshot = self.snapshot(window, cx);
11244        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11245
11246        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11247    }
11248
11249    pub(crate) fn breakpoint_at_anchor(
11250        &self,
11251        breakpoint_position: Anchor,
11252        snapshot: &EditorSnapshot,
11253        cx: &mut Context<Self>,
11254    ) -> Option<(Anchor, Breakpoint)> {
11255        let buffer = self
11256            .buffer
11257            .read(cx)
11258            .buffer_for_anchor(breakpoint_position, cx)?;
11259
11260        let enclosing_excerpt = breakpoint_position.excerpt_id;
11261        let buffer_snapshot = buffer.read(cx).snapshot();
11262
11263        let row = buffer_snapshot
11264            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11265            .row;
11266
11267        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11268        let anchor_end = snapshot
11269            .buffer_snapshot()
11270            .anchor_after(Point::new(row, line_len));
11271
11272        self.breakpoint_store
11273            .as_ref()?
11274            .read_with(cx, |breakpoint_store, cx| {
11275                breakpoint_store
11276                    .breakpoints(
11277                        &buffer,
11278                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11279                        &buffer_snapshot,
11280                        cx,
11281                    )
11282                    .next()
11283                    .and_then(|(bp, _)| {
11284                        let breakpoint_row = buffer_snapshot
11285                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11286                            .row;
11287
11288                        if breakpoint_row == row {
11289                            snapshot
11290                                .buffer_snapshot()
11291                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11292                                .map(|position| (position, bp.bp.clone()))
11293                        } else {
11294                            None
11295                        }
11296                    })
11297            })
11298    }
11299
11300    pub fn edit_log_breakpoint(
11301        &mut self,
11302        _: &EditLogBreakpoint,
11303        window: &mut Window,
11304        cx: &mut Context<Self>,
11305    ) {
11306        if self.breakpoint_store.is_none() {
11307            return;
11308        }
11309
11310        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11311            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11312                message: None,
11313                state: BreakpointState::Enabled,
11314                condition: None,
11315                hit_condition: None,
11316            });
11317
11318            self.add_edit_breakpoint_block(
11319                anchor,
11320                &breakpoint,
11321                BreakpointPromptEditAction::Log,
11322                window,
11323                cx,
11324            );
11325        }
11326    }
11327
11328    fn breakpoints_at_cursors(
11329        &self,
11330        window: &mut Window,
11331        cx: &mut Context<Self>,
11332    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11333        let snapshot = self.snapshot(window, cx);
11334        let cursors = self
11335            .selections
11336            .disjoint_anchors_arc()
11337            .iter()
11338            .map(|selection| {
11339                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11340
11341                let breakpoint_position = self
11342                    .breakpoint_at_row(cursor_position.row, window, cx)
11343                    .map(|bp| bp.0)
11344                    .unwrap_or_else(|| {
11345                        snapshot
11346                            .display_snapshot
11347                            .buffer_snapshot()
11348                            .anchor_after(Point::new(cursor_position.row, 0))
11349                    });
11350
11351                let breakpoint = self
11352                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11353                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11354
11355                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11356            })
11357            // 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.
11358            .collect::<HashMap<Anchor, _>>();
11359
11360        cursors.into_iter().collect()
11361    }
11362
11363    pub fn enable_breakpoint(
11364        &mut self,
11365        _: &crate::actions::EnableBreakpoint,
11366        window: &mut Window,
11367        cx: &mut Context<Self>,
11368    ) {
11369        if self.breakpoint_store.is_none() {
11370            return;
11371        }
11372
11373        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11374            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11375                continue;
11376            };
11377            self.edit_breakpoint_at_anchor(
11378                anchor,
11379                breakpoint,
11380                BreakpointEditAction::InvertState,
11381                cx,
11382            );
11383        }
11384    }
11385
11386    pub fn disable_breakpoint(
11387        &mut self,
11388        _: &crate::actions::DisableBreakpoint,
11389        window: &mut Window,
11390        cx: &mut Context<Self>,
11391    ) {
11392        if self.breakpoint_store.is_none() {
11393            return;
11394        }
11395
11396        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11397            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11398                continue;
11399            };
11400            self.edit_breakpoint_at_anchor(
11401                anchor,
11402                breakpoint,
11403                BreakpointEditAction::InvertState,
11404                cx,
11405            );
11406        }
11407    }
11408
11409    pub fn toggle_breakpoint(
11410        &mut self,
11411        _: &crate::actions::ToggleBreakpoint,
11412        window: &mut Window,
11413        cx: &mut Context<Self>,
11414    ) {
11415        if self.breakpoint_store.is_none() {
11416            return;
11417        }
11418
11419        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11420            if let Some(breakpoint) = breakpoint {
11421                self.edit_breakpoint_at_anchor(
11422                    anchor,
11423                    breakpoint,
11424                    BreakpointEditAction::Toggle,
11425                    cx,
11426                );
11427            } else {
11428                self.edit_breakpoint_at_anchor(
11429                    anchor,
11430                    Breakpoint::new_standard(),
11431                    BreakpointEditAction::Toggle,
11432                    cx,
11433                );
11434            }
11435        }
11436    }
11437
11438    pub fn edit_breakpoint_at_anchor(
11439        &mut self,
11440        breakpoint_position: Anchor,
11441        breakpoint: Breakpoint,
11442        edit_action: BreakpointEditAction,
11443        cx: &mut Context<Self>,
11444    ) {
11445        let Some(breakpoint_store) = &self.breakpoint_store else {
11446            return;
11447        };
11448
11449        let Some(buffer) = self
11450            .buffer
11451            .read(cx)
11452            .buffer_for_anchor(breakpoint_position, cx)
11453        else {
11454            return;
11455        };
11456
11457        breakpoint_store.update(cx, |breakpoint_store, cx| {
11458            breakpoint_store.toggle_breakpoint(
11459                buffer,
11460                BreakpointWithPosition {
11461                    position: breakpoint_position.text_anchor,
11462                    bp: breakpoint,
11463                },
11464                edit_action,
11465                cx,
11466            );
11467        });
11468
11469        cx.notify();
11470    }
11471
11472    #[cfg(any(test, feature = "test-support"))]
11473    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11474        self.breakpoint_store.clone()
11475    }
11476
11477    pub fn prepare_restore_change(
11478        &self,
11479        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11480        hunk: &MultiBufferDiffHunk,
11481        cx: &mut App,
11482    ) -> Option<()> {
11483        if hunk.is_created_file() {
11484            return None;
11485        }
11486        let buffer = self.buffer.read(cx);
11487        let diff = buffer.diff_for(hunk.buffer_id)?;
11488        let buffer = buffer.buffer(hunk.buffer_id)?;
11489        let buffer = buffer.read(cx);
11490        let original_text = diff
11491            .read(cx)
11492            .base_text()
11493            .as_rope()
11494            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11495        let buffer_snapshot = buffer.snapshot();
11496        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11497        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11498            probe
11499                .0
11500                .start
11501                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11502                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11503        }) {
11504            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11505            Some(())
11506        } else {
11507            None
11508        }
11509    }
11510
11511    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11512        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11513    }
11514
11515    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11516        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11517    }
11518
11519    fn manipulate_lines<M>(
11520        &mut self,
11521        window: &mut Window,
11522        cx: &mut Context<Self>,
11523        mut manipulate: M,
11524    ) where
11525        M: FnMut(&str) -> LineManipulationResult,
11526    {
11527        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11528
11529        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11530        let buffer = self.buffer.read(cx).snapshot(cx);
11531
11532        let mut edits = Vec::new();
11533
11534        let selections = self.selections.all::<Point>(&display_map);
11535        let mut selections = selections.iter().peekable();
11536        let mut contiguous_row_selections = Vec::new();
11537        let mut new_selections = Vec::new();
11538        let mut added_lines = 0;
11539        let mut removed_lines = 0;
11540
11541        while let Some(selection) = selections.next() {
11542            let (start_row, end_row) = consume_contiguous_rows(
11543                &mut contiguous_row_selections,
11544                selection,
11545                &display_map,
11546                &mut selections,
11547            );
11548
11549            let start_point = Point::new(start_row.0, 0);
11550            let end_point = Point::new(
11551                end_row.previous_row().0,
11552                buffer.line_len(end_row.previous_row()),
11553            );
11554            let text = buffer
11555                .text_for_range(start_point..end_point)
11556                .collect::<String>();
11557
11558            let LineManipulationResult {
11559                new_text,
11560                line_count_before,
11561                line_count_after,
11562            } = manipulate(&text);
11563
11564            edits.push((start_point..end_point, new_text));
11565
11566            // Selections must change based on added and removed line count
11567            let start_row =
11568                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11569            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11570            new_selections.push(Selection {
11571                id: selection.id,
11572                start: start_row,
11573                end: end_row,
11574                goal: SelectionGoal::None,
11575                reversed: selection.reversed,
11576            });
11577
11578            if line_count_after > line_count_before {
11579                added_lines += line_count_after - line_count_before;
11580            } else if line_count_before > line_count_after {
11581                removed_lines += line_count_before - line_count_after;
11582            }
11583        }
11584
11585        self.transact(window, cx, |this, window, cx| {
11586            let buffer = this.buffer.update(cx, |buffer, cx| {
11587                buffer.edit(edits, None, cx);
11588                buffer.snapshot(cx)
11589            });
11590
11591            // Recalculate offsets on newly edited buffer
11592            let new_selections = new_selections
11593                .iter()
11594                .map(|s| {
11595                    let start_point = Point::new(s.start.0, 0);
11596                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11597                    Selection {
11598                        id: s.id,
11599                        start: buffer.point_to_offset(start_point),
11600                        end: buffer.point_to_offset(end_point),
11601                        goal: s.goal,
11602                        reversed: s.reversed,
11603                    }
11604                })
11605                .collect();
11606
11607            this.change_selections(Default::default(), window, cx, |s| {
11608                s.select(new_selections);
11609            });
11610
11611            this.request_autoscroll(Autoscroll::fit(), cx);
11612        });
11613    }
11614
11615    fn manipulate_immutable_lines<Fn>(
11616        &mut self,
11617        window: &mut Window,
11618        cx: &mut Context<Self>,
11619        mut callback: Fn,
11620    ) where
11621        Fn: FnMut(&mut Vec<&str>),
11622    {
11623        self.manipulate_lines(window, cx, |text| {
11624            let mut lines: Vec<&str> = text.split('\n').collect();
11625            let line_count_before = lines.len();
11626
11627            callback(&mut lines);
11628
11629            LineManipulationResult {
11630                new_text: lines.join("\n"),
11631                line_count_before,
11632                line_count_after: lines.len(),
11633            }
11634        });
11635    }
11636
11637    fn manipulate_mutable_lines<Fn>(
11638        &mut self,
11639        window: &mut Window,
11640        cx: &mut Context<Self>,
11641        mut callback: Fn,
11642    ) where
11643        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11644    {
11645        self.manipulate_lines(window, cx, |text| {
11646            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11647            let line_count_before = lines.len();
11648
11649            callback(&mut lines);
11650
11651            LineManipulationResult {
11652                new_text: lines.join("\n"),
11653                line_count_before,
11654                line_count_after: lines.len(),
11655            }
11656        });
11657    }
11658
11659    pub fn convert_indentation_to_spaces(
11660        &mut self,
11661        _: &ConvertIndentationToSpaces,
11662        window: &mut Window,
11663        cx: &mut Context<Self>,
11664    ) {
11665        let settings = self.buffer.read(cx).language_settings(cx);
11666        let tab_size = settings.tab_size.get() as usize;
11667
11668        self.manipulate_mutable_lines(window, cx, |lines| {
11669            // Allocates a reasonably sized scratch buffer once for the whole loop
11670            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11671            // Avoids recomputing spaces that could be inserted many times
11672            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11673                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11674                .collect();
11675
11676            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11677                let mut chars = line.as_ref().chars();
11678                let mut col = 0;
11679                let mut changed = false;
11680
11681                for ch in chars.by_ref() {
11682                    match ch {
11683                        ' ' => {
11684                            reindented_line.push(' ');
11685                            col += 1;
11686                        }
11687                        '\t' => {
11688                            // \t are converted to spaces depending on the current column
11689                            let spaces_len = tab_size - (col % tab_size);
11690                            reindented_line.extend(&space_cache[spaces_len - 1]);
11691                            col += spaces_len;
11692                            changed = true;
11693                        }
11694                        _ => {
11695                            // If we dont append before break, the character is consumed
11696                            reindented_line.push(ch);
11697                            break;
11698                        }
11699                    }
11700                }
11701
11702                if !changed {
11703                    reindented_line.clear();
11704                    continue;
11705                }
11706                // Append the rest of the line and replace old reference with new one
11707                reindented_line.extend(chars);
11708                *line = Cow::Owned(reindented_line.clone());
11709                reindented_line.clear();
11710            }
11711        });
11712    }
11713
11714    pub fn convert_indentation_to_tabs(
11715        &mut self,
11716        _: &ConvertIndentationToTabs,
11717        window: &mut Window,
11718        cx: &mut Context<Self>,
11719    ) {
11720        let settings = self.buffer.read(cx).language_settings(cx);
11721        let tab_size = settings.tab_size.get() as usize;
11722
11723        self.manipulate_mutable_lines(window, cx, |lines| {
11724            // Allocates a reasonably sized buffer once for the whole loop
11725            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11726            // Avoids recomputing spaces that could be inserted many times
11727            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11728                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11729                .collect();
11730
11731            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11732                let mut chars = line.chars();
11733                let mut spaces_count = 0;
11734                let mut first_non_indent_char = None;
11735                let mut changed = false;
11736
11737                for ch in chars.by_ref() {
11738                    match ch {
11739                        ' ' => {
11740                            // Keep track of spaces. Append \t when we reach tab_size
11741                            spaces_count += 1;
11742                            changed = true;
11743                            if spaces_count == tab_size {
11744                                reindented_line.push('\t');
11745                                spaces_count = 0;
11746                            }
11747                        }
11748                        '\t' => {
11749                            reindented_line.push('\t');
11750                            spaces_count = 0;
11751                        }
11752                        _ => {
11753                            // Dont append it yet, we might have remaining spaces
11754                            first_non_indent_char = Some(ch);
11755                            break;
11756                        }
11757                    }
11758                }
11759
11760                if !changed {
11761                    reindented_line.clear();
11762                    continue;
11763                }
11764                // Remaining spaces that didn't make a full tab stop
11765                if spaces_count > 0 {
11766                    reindented_line.extend(&space_cache[spaces_count - 1]);
11767                }
11768                // If we consume an extra character that was not indentation, add it back
11769                if let Some(extra_char) = first_non_indent_char {
11770                    reindented_line.push(extra_char);
11771                }
11772                // Append the rest of the line and replace old reference with new one
11773                reindented_line.extend(chars);
11774                *line = Cow::Owned(reindented_line.clone());
11775                reindented_line.clear();
11776            }
11777        });
11778    }
11779
11780    pub fn convert_to_upper_case(
11781        &mut self,
11782        _: &ConvertToUpperCase,
11783        window: &mut Window,
11784        cx: &mut Context<Self>,
11785    ) {
11786        self.manipulate_text(window, cx, |text| text.to_uppercase())
11787    }
11788
11789    pub fn convert_to_lower_case(
11790        &mut self,
11791        _: &ConvertToLowerCase,
11792        window: &mut Window,
11793        cx: &mut Context<Self>,
11794    ) {
11795        self.manipulate_text(window, cx, |text| text.to_lowercase())
11796    }
11797
11798    pub fn convert_to_title_case(
11799        &mut self,
11800        _: &ConvertToTitleCase,
11801        window: &mut Window,
11802        cx: &mut Context<Self>,
11803    ) {
11804        self.manipulate_text(window, cx, |text| {
11805            text.split('\n')
11806                .map(|line| line.to_case(Case::Title))
11807                .join("\n")
11808        })
11809    }
11810
11811    pub fn convert_to_snake_case(
11812        &mut self,
11813        _: &ConvertToSnakeCase,
11814        window: &mut Window,
11815        cx: &mut Context<Self>,
11816    ) {
11817        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11818    }
11819
11820    pub fn convert_to_kebab_case(
11821        &mut self,
11822        _: &ConvertToKebabCase,
11823        window: &mut Window,
11824        cx: &mut Context<Self>,
11825    ) {
11826        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11827    }
11828
11829    pub fn convert_to_upper_camel_case(
11830        &mut self,
11831        _: &ConvertToUpperCamelCase,
11832        window: &mut Window,
11833        cx: &mut Context<Self>,
11834    ) {
11835        self.manipulate_text(window, cx, |text| {
11836            text.split('\n')
11837                .map(|line| line.to_case(Case::UpperCamel))
11838                .join("\n")
11839        })
11840    }
11841
11842    pub fn convert_to_lower_camel_case(
11843        &mut self,
11844        _: &ConvertToLowerCamelCase,
11845        window: &mut Window,
11846        cx: &mut Context<Self>,
11847    ) {
11848        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11849    }
11850
11851    pub fn convert_to_opposite_case(
11852        &mut self,
11853        _: &ConvertToOppositeCase,
11854        window: &mut Window,
11855        cx: &mut Context<Self>,
11856    ) {
11857        self.manipulate_text(window, cx, |text| {
11858            text.chars()
11859                .fold(String::with_capacity(text.len()), |mut t, c| {
11860                    if c.is_uppercase() {
11861                        t.extend(c.to_lowercase());
11862                    } else {
11863                        t.extend(c.to_uppercase());
11864                    }
11865                    t
11866                })
11867        })
11868    }
11869
11870    pub fn convert_to_sentence_case(
11871        &mut self,
11872        _: &ConvertToSentenceCase,
11873        window: &mut Window,
11874        cx: &mut Context<Self>,
11875    ) {
11876        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11877    }
11878
11879    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11880        self.manipulate_text(window, cx, |text| {
11881            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11882            if has_upper_case_characters {
11883                text.to_lowercase()
11884            } else {
11885                text.to_uppercase()
11886            }
11887        })
11888    }
11889
11890    pub fn convert_to_rot13(
11891        &mut self,
11892        _: &ConvertToRot13,
11893        window: &mut Window,
11894        cx: &mut Context<Self>,
11895    ) {
11896        self.manipulate_text(window, cx, |text| {
11897            text.chars()
11898                .map(|c| match c {
11899                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11900                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11901                    _ => c,
11902                })
11903                .collect()
11904        })
11905    }
11906
11907    pub fn convert_to_rot47(
11908        &mut self,
11909        _: &ConvertToRot47,
11910        window: &mut Window,
11911        cx: &mut Context<Self>,
11912    ) {
11913        self.manipulate_text(window, cx, |text| {
11914            text.chars()
11915                .map(|c| {
11916                    let code_point = c as u32;
11917                    if code_point >= 33 && code_point <= 126 {
11918                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11919                    }
11920                    c
11921                })
11922                .collect()
11923        })
11924    }
11925
11926    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11927    where
11928        Fn: FnMut(&str) -> String,
11929    {
11930        let buffer = self.buffer.read(cx).snapshot(cx);
11931
11932        let mut new_selections = Vec::new();
11933        let mut edits = Vec::new();
11934        let mut selection_adjustment = 0isize;
11935
11936        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11937            let selection_is_empty = selection.is_empty();
11938
11939            let (start, end) = if selection_is_empty {
11940                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11941                (word_range.start, word_range.end)
11942            } else {
11943                (
11944                    buffer.point_to_offset(selection.start),
11945                    buffer.point_to_offset(selection.end),
11946                )
11947            };
11948
11949            let text = buffer.text_for_range(start..end).collect::<String>();
11950            let old_length = text.len() as isize;
11951            let text = callback(&text);
11952
11953            new_selections.push(Selection {
11954                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
11955                end: MultiBufferOffset(
11956                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
11957                ),
11958                goal: SelectionGoal::None,
11959                id: selection.id,
11960                reversed: selection.reversed,
11961            });
11962
11963            selection_adjustment += old_length - text.len() as isize;
11964
11965            edits.push((start..end, text));
11966        }
11967
11968        self.transact(window, cx, |this, window, cx| {
11969            this.buffer.update(cx, |buffer, cx| {
11970                buffer.edit(edits, None, cx);
11971            });
11972
11973            this.change_selections(Default::default(), window, cx, |s| {
11974                s.select(new_selections);
11975            });
11976
11977            this.request_autoscroll(Autoscroll::fit(), cx);
11978        });
11979    }
11980
11981    pub fn move_selection_on_drop(
11982        &mut self,
11983        selection: &Selection<Anchor>,
11984        target: DisplayPoint,
11985        is_cut: bool,
11986        window: &mut Window,
11987        cx: &mut Context<Self>,
11988    ) {
11989        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11990        let buffer = display_map.buffer_snapshot();
11991        let mut edits = Vec::new();
11992        let insert_point = display_map
11993            .clip_point(target, Bias::Left)
11994            .to_point(&display_map);
11995        let text = buffer
11996            .text_for_range(selection.start..selection.end)
11997            .collect::<String>();
11998        if is_cut {
11999            edits.push(((selection.start..selection.end), String::new()));
12000        }
12001        let insert_anchor = buffer.anchor_before(insert_point);
12002        edits.push(((insert_anchor..insert_anchor), text));
12003        let last_edit_start = insert_anchor.bias_left(buffer);
12004        let last_edit_end = insert_anchor.bias_right(buffer);
12005        self.transact(window, cx, |this, window, cx| {
12006            this.buffer.update(cx, |buffer, cx| {
12007                buffer.edit(edits, None, cx);
12008            });
12009            this.change_selections(Default::default(), window, cx, |s| {
12010                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12011            });
12012        });
12013    }
12014
12015    pub fn clear_selection_drag_state(&mut self) {
12016        self.selection_drag_state = SelectionDragState::None;
12017    }
12018
12019    pub fn duplicate(
12020        &mut self,
12021        upwards: bool,
12022        whole_lines: bool,
12023        window: &mut Window,
12024        cx: &mut Context<Self>,
12025    ) {
12026        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12027
12028        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12029        let buffer = display_map.buffer_snapshot();
12030        let selections = self.selections.all::<Point>(&display_map);
12031
12032        let mut edits = Vec::new();
12033        let mut selections_iter = selections.iter().peekable();
12034        while let Some(selection) = selections_iter.next() {
12035            let mut rows = selection.spanned_rows(false, &display_map);
12036            // duplicate line-wise
12037            if whole_lines || selection.start == selection.end {
12038                // Avoid duplicating the same lines twice.
12039                while let Some(next_selection) = selections_iter.peek() {
12040                    let next_rows = next_selection.spanned_rows(false, &display_map);
12041                    if next_rows.start < rows.end {
12042                        rows.end = next_rows.end;
12043                        selections_iter.next().unwrap();
12044                    } else {
12045                        break;
12046                    }
12047                }
12048
12049                // Copy the text from the selected row region and splice it either at the start
12050                // or end of the region.
12051                let start = Point::new(rows.start.0, 0);
12052                let end = Point::new(
12053                    rows.end.previous_row().0,
12054                    buffer.line_len(rows.end.previous_row()),
12055                );
12056
12057                let mut text = buffer.text_for_range(start..end).collect::<String>();
12058
12059                let insert_location = if upwards {
12060                    // When duplicating upward, we need to insert before the current line.
12061                    // If we're on the last line and it doesn't end with a newline,
12062                    // we need to add a newline before the duplicated content.
12063                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12064                        && buffer.max_point().column > 0
12065                        && !text.ends_with('\n');
12066
12067                    if needs_leading_newline {
12068                        text.insert(0, '\n');
12069                        end
12070                    } else {
12071                        text.push('\n');
12072                        Point::new(rows.start.0, 0)
12073                    }
12074                } else {
12075                    text.push('\n');
12076                    start
12077                };
12078                edits.push((insert_location..insert_location, text));
12079            } else {
12080                // duplicate character-wise
12081                let start = selection.start;
12082                let end = selection.end;
12083                let text = buffer.text_for_range(start..end).collect::<String>();
12084                edits.push((selection.end..selection.end, text));
12085            }
12086        }
12087
12088        self.transact(window, cx, |this, window, cx| {
12089            this.buffer.update(cx, |buffer, cx| {
12090                buffer.edit(edits, None, cx);
12091            });
12092
12093            // When duplicating upward with whole lines, move the cursor to the duplicated line
12094            if upwards && whole_lines {
12095                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12096
12097                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12098                    let mut new_ranges = Vec::new();
12099                    let selections = s.all::<Point>(&display_map);
12100                    let mut selections_iter = selections.iter().peekable();
12101
12102                    while let Some(first_selection) = selections_iter.next() {
12103                        // Group contiguous selections together to find the total row span
12104                        let mut group_selections = vec![first_selection];
12105                        let mut rows = first_selection.spanned_rows(false, &display_map);
12106
12107                        while let Some(next_selection) = selections_iter.peek() {
12108                            let next_rows = next_selection.spanned_rows(false, &display_map);
12109                            if next_rows.start < rows.end {
12110                                rows.end = next_rows.end;
12111                                group_selections.push(selections_iter.next().unwrap());
12112                            } else {
12113                                break;
12114                            }
12115                        }
12116
12117                        let row_count = rows.end.0 - rows.start.0;
12118
12119                        // Move all selections in this group up by the total number of duplicated rows
12120                        for selection in group_selections {
12121                            let new_start = Point::new(
12122                                selection.start.row.saturating_sub(row_count),
12123                                selection.start.column,
12124                            );
12125
12126                            let new_end = Point::new(
12127                                selection.end.row.saturating_sub(row_count),
12128                                selection.end.column,
12129                            );
12130
12131                            new_ranges.push(new_start..new_end);
12132                        }
12133                    }
12134
12135                    s.select_ranges(new_ranges);
12136                });
12137            }
12138
12139            this.request_autoscroll(Autoscroll::fit(), cx);
12140        });
12141    }
12142
12143    pub fn duplicate_line_up(
12144        &mut self,
12145        _: &DuplicateLineUp,
12146        window: &mut Window,
12147        cx: &mut Context<Self>,
12148    ) {
12149        self.duplicate(true, true, window, cx);
12150    }
12151
12152    pub fn duplicate_line_down(
12153        &mut self,
12154        _: &DuplicateLineDown,
12155        window: &mut Window,
12156        cx: &mut Context<Self>,
12157    ) {
12158        self.duplicate(false, true, window, cx);
12159    }
12160
12161    pub fn duplicate_selection(
12162        &mut self,
12163        _: &DuplicateSelection,
12164        window: &mut Window,
12165        cx: &mut Context<Self>,
12166    ) {
12167        self.duplicate(false, false, window, cx);
12168    }
12169
12170    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12171        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12172        if self.mode.is_single_line() {
12173            cx.propagate();
12174            return;
12175        }
12176
12177        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12178        let buffer = self.buffer.read(cx).snapshot(cx);
12179
12180        let mut edits = Vec::new();
12181        let mut unfold_ranges = Vec::new();
12182        let mut refold_creases = Vec::new();
12183
12184        let selections = self.selections.all::<Point>(&display_map);
12185        let mut selections = selections.iter().peekable();
12186        let mut contiguous_row_selections = Vec::new();
12187        let mut new_selections = Vec::new();
12188
12189        while let Some(selection) = selections.next() {
12190            // Find all the selections that span a contiguous row range
12191            let (start_row, end_row) = consume_contiguous_rows(
12192                &mut contiguous_row_selections,
12193                selection,
12194                &display_map,
12195                &mut selections,
12196            );
12197
12198            // Move the text spanned by the row range to be before the line preceding the row range
12199            if start_row.0 > 0 {
12200                let range_to_move = Point::new(
12201                    start_row.previous_row().0,
12202                    buffer.line_len(start_row.previous_row()),
12203                )
12204                    ..Point::new(
12205                        end_row.previous_row().0,
12206                        buffer.line_len(end_row.previous_row()),
12207                    );
12208                let insertion_point = display_map
12209                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12210                    .0;
12211
12212                // Don't move lines across excerpts
12213                if buffer
12214                    .excerpt_containing(insertion_point..range_to_move.end)
12215                    .is_some()
12216                {
12217                    let text = buffer
12218                        .text_for_range(range_to_move.clone())
12219                        .flat_map(|s| s.chars())
12220                        .skip(1)
12221                        .chain(['\n'])
12222                        .collect::<String>();
12223
12224                    edits.push((
12225                        buffer.anchor_after(range_to_move.start)
12226                            ..buffer.anchor_before(range_to_move.end),
12227                        String::new(),
12228                    ));
12229                    let insertion_anchor = buffer.anchor_after(insertion_point);
12230                    edits.push((insertion_anchor..insertion_anchor, text));
12231
12232                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12233
12234                    // Move selections up
12235                    new_selections.extend(contiguous_row_selections.drain(..).map(
12236                        |mut selection| {
12237                            selection.start.row -= row_delta;
12238                            selection.end.row -= row_delta;
12239                            selection
12240                        },
12241                    ));
12242
12243                    // Move folds up
12244                    unfold_ranges.push(range_to_move.clone());
12245                    for fold in display_map.folds_in_range(
12246                        buffer.anchor_before(range_to_move.start)
12247                            ..buffer.anchor_after(range_to_move.end),
12248                    ) {
12249                        let mut start = fold.range.start.to_point(&buffer);
12250                        let mut end = fold.range.end.to_point(&buffer);
12251                        start.row -= row_delta;
12252                        end.row -= row_delta;
12253                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12254                    }
12255                }
12256            }
12257
12258            // If we didn't move line(s), preserve the existing selections
12259            new_selections.append(&mut contiguous_row_selections);
12260        }
12261
12262        self.transact(window, cx, |this, window, cx| {
12263            this.unfold_ranges(&unfold_ranges, true, true, cx);
12264            this.buffer.update(cx, |buffer, cx| {
12265                for (range, text) in edits {
12266                    buffer.edit([(range, text)], None, cx);
12267                }
12268            });
12269            this.fold_creases(refold_creases, true, window, cx);
12270            this.change_selections(Default::default(), window, cx, |s| {
12271                s.select(new_selections);
12272            })
12273        });
12274    }
12275
12276    pub fn move_line_down(
12277        &mut self,
12278        _: &MoveLineDown,
12279        window: &mut Window,
12280        cx: &mut Context<Self>,
12281    ) {
12282        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12283        if self.mode.is_single_line() {
12284            cx.propagate();
12285            return;
12286        }
12287
12288        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12289        let buffer = self.buffer.read(cx).snapshot(cx);
12290
12291        let mut edits = Vec::new();
12292        let mut unfold_ranges = Vec::new();
12293        let mut refold_creases = Vec::new();
12294
12295        let selections = self.selections.all::<Point>(&display_map);
12296        let mut selections = selections.iter().peekable();
12297        let mut contiguous_row_selections = Vec::new();
12298        let mut new_selections = Vec::new();
12299
12300        while let Some(selection) = selections.next() {
12301            // Find all the selections that span a contiguous row range
12302            let (start_row, end_row) = consume_contiguous_rows(
12303                &mut contiguous_row_selections,
12304                selection,
12305                &display_map,
12306                &mut selections,
12307            );
12308
12309            // Move the text spanned by the row range to be after the last line of the row range
12310            if end_row.0 <= buffer.max_point().row {
12311                let range_to_move =
12312                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12313                let insertion_point = display_map
12314                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12315                    .0;
12316
12317                // Don't move lines across excerpt boundaries
12318                if buffer
12319                    .excerpt_containing(range_to_move.start..insertion_point)
12320                    .is_some()
12321                {
12322                    let mut text = String::from("\n");
12323                    text.extend(buffer.text_for_range(range_to_move.clone()));
12324                    text.pop(); // Drop trailing newline
12325                    edits.push((
12326                        buffer.anchor_after(range_to_move.start)
12327                            ..buffer.anchor_before(range_to_move.end),
12328                        String::new(),
12329                    ));
12330                    let insertion_anchor = buffer.anchor_after(insertion_point);
12331                    edits.push((insertion_anchor..insertion_anchor, text));
12332
12333                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12334
12335                    // Move selections down
12336                    new_selections.extend(contiguous_row_selections.drain(..).map(
12337                        |mut selection| {
12338                            selection.start.row += row_delta;
12339                            selection.end.row += row_delta;
12340                            selection
12341                        },
12342                    ));
12343
12344                    // Move folds down
12345                    unfold_ranges.push(range_to_move.clone());
12346                    for fold in display_map.folds_in_range(
12347                        buffer.anchor_before(range_to_move.start)
12348                            ..buffer.anchor_after(range_to_move.end),
12349                    ) {
12350                        let mut start = fold.range.start.to_point(&buffer);
12351                        let mut end = fold.range.end.to_point(&buffer);
12352                        start.row += row_delta;
12353                        end.row += row_delta;
12354                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12355                    }
12356                }
12357            }
12358
12359            // If we didn't move line(s), preserve the existing selections
12360            new_selections.append(&mut contiguous_row_selections);
12361        }
12362
12363        self.transact(window, cx, |this, window, cx| {
12364            this.unfold_ranges(&unfold_ranges, true, true, cx);
12365            this.buffer.update(cx, |buffer, cx| {
12366                for (range, text) in edits {
12367                    buffer.edit([(range, text)], None, cx);
12368                }
12369            });
12370            this.fold_creases(refold_creases, true, window, cx);
12371            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12372        });
12373    }
12374
12375    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12376        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12377        let text_layout_details = &self.text_layout_details(window);
12378        self.transact(window, cx, |this, window, cx| {
12379            let edits = this.change_selections(Default::default(), window, cx, |s| {
12380                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12381                s.move_with(|display_map, selection| {
12382                    if !selection.is_empty() {
12383                        return;
12384                    }
12385
12386                    let mut head = selection.head();
12387                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12388                    if head.column() == display_map.line_len(head.row()) {
12389                        transpose_offset = display_map
12390                            .buffer_snapshot()
12391                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12392                    }
12393
12394                    if transpose_offset == MultiBufferOffset(0) {
12395                        return;
12396                    }
12397
12398                    *head.column_mut() += 1;
12399                    head = display_map.clip_point(head, Bias::Right);
12400                    let goal = SelectionGoal::HorizontalPosition(
12401                        display_map
12402                            .x_for_display_point(head, text_layout_details)
12403                            .into(),
12404                    );
12405                    selection.collapse_to(head, goal);
12406
12407                    let transpose_start = display_map
12408                        .buffer_snapshot()
12409                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12410                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12411                        let transpose_end = display_map
12412                            .buffer_snapshot()
12413                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12414                        if let Some(ch) = display_map
12415                            .buffer_snapshot()
12416                            .chars_at(transpose_start)
12417                            .next()
12418                        {
12419                            edits.push((transpose_start..transpose_offset, String::new()));
12420                            edits.push((transpose_end..transpose_end, ch.to_string()));
12421                        }
12422                    }
12423                });
12424                edits
12425            });
12426            this.buffer
12427                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12428            let selections = this
12429                .selections
12430                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12431            this.change_selections(Default::default(), window, cx, |s| {
12432                s.select(selections);
12433            });
12434        });
12435    }
12436
12437    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12438        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12439        if self.mode.is_single_line() {
12440            cx.propagate();
12441            return;
12442        }
12443
12444        self.rewrap_impl(RewrapOptions::default(), cx)
12445    }
12446
12447    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12448        let buffer = self.buffer.read(cx).snapshot(cx);
12449        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12450
12451        #[derive(Clone, Debug, PartialEq)]
12452        enum CommentFormat {
12453            /// single line comment, with prefix for line
12454            Line(String),
12455            /// single line within a block comment, with prefix for line
12456            BlockLine(String),
12457            /// a single line of a block comment that includes the initial delimiter
12458            BlockCommentWithStart(BlockCommentConfig),
12459            /// a single line of a block comment that includes the ending delimiter
12460            BlockCommentWithEnd(BlockCommentConfig),
12461        }
12462
12463        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12464        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12465            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12466                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12467                .peekable();
12468
12469            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12470                row
12471            } else {
12472                return Vec::new();
12473            };
12474
12475            let language_settings = buffer.language_settings_at(selection.head(), cx);
12476            let language_scope = buffer.language_scope_at(selection.head());
12477
12478            let indent_and_prefix_for_row =
12479                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12480                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12481                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12482                        &language_scope
12483                    {
12484                        let indent_end = Point::new(row, indent.len);
12485                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12486                        let line_text_after_indent = buffer
12487                            .text_for_range(indent_end..line_end)
12488                            .collect::<String>();
12489
12490                        let is_within_comment_override = buffer
12491                            .language_scope_at(indent_end)
12492                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12493                        let comment_delimiters = if is_within_comment_override {
12494                            // we are within a comment syntax node, but we don't
12495                            // yet know what kind of comment: block, doc or line
12496                            match (
12497                                language_scope.documentation_comment(),
12498                                language_scope.block_comment(),
12499                            ) {
12500                                (Some(config), _) | (_, Some(config))
12501                                    if buffer.contains_str_at(indent_end, &config.start) =>
12502                                {
12503                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12504                                }
12505                                (Some(config), _) | (_, Some(config))
12506                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12507                                {
12508                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12509                                }
12510                                (Some(config), _) | (_, Some(config))
12511                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12512                                {
12513                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12514                                }
12515                                (_, _) => language_scope
12516                                    .line_comment_prefixes()
12517                                    .iter()
12518                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12519                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12520                            }
12521                        } else {
12522                            // we not in an overridden comment node, but we may
12523                            // be within a non-overridden line comment node
12524                            language_scope
12525                                .line_comment_prefixes()
12526                                .iter()
12527                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12528                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12529                        };
12530
12531                        let rewrap_prefix = language_scope
12532                            .rewrap_prefixes()
12533                            .iter()
12534                            .find_map(|prefix_regex| {
12535                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12536                                    if mat.start() == 0 {
12537                                        Some(mat.as_str().to_string())
12538                                    } else {
12539                                        None
12540                                    }
12541                                })
12542                            })
12543                            .flatten();
12544                        (comment_delimiters, rewrap_prefix)
12545                    } else {
12546                        (None, None)
12547                    };
12548                    (indent, comment_prefix, rewrap_prefix)
12549                };
12550
12551            let mut ranges = Vec::new();
12552            let from_empty_selection = selection.is_empty();
12553
12554            let mut current_range_start = first_row;
12555            let mut prev_row = first_row;
12556            let (
12557                mut current_range_indent,
12558                mut current_range_comment_delimiters,
12559                mut current_range_rewrap_prefix,
12560            ) = indent_and_prefix_for_row(first_row);
12561
12562            for row in non_blank_rows_iter.skip(1) {
12563                let has_paragraph_break = row > prev_row + 1;
12564
12565                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12566                    indent_and_prefix_for_row(row);
12567
12568                let has_indent_change = row_indent != current_range_indent;
12569                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12570
12571                let has_boundary_change = has_comment_change
12572                    || row_rewrap_prefix.is_some()
12573                    || (has_indent_change && current_range_comment_delimiters.is_some());
12574
12575                if has_paragraph_break || has_boundary_change {
12576                    ranges.push((
12577                        language_settings.clone(),
12578                        Point::new(current_range_start, 0)
12579                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12580                        current_range_indent,
12581                        current_range_comment_delimiters.clone(),
12582                        current_range_rewrap_prefix.clone(),
12583                        from_empty_selection,
12584                    ));
12585                    current_range_start = row;
12586                    current_range_indent = row_indent;
12587                    current_range_comment_delimiters = row_comment_delimiters;
12588                    current_range_rewrap_prefix = row_rewrap_prefix;
12589                }
12590                prev_row = row;
12591            }
12592
12593            ranges.push((
12594                language_settings.clone(),
12595                Point::new(current_range_start, 0)
12596                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12597                current_range_indent,
12598                current_range_comment_delimiters,
12599                current_range_rewrap_prefix,
12600                from_empty_selection,
12601            ));
12602
12603            ranges
12604        });
12605
12606        let mut edits = Vec::new();
12607        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12608
12609        for (
12610            language_settings,
12611            wrap_range,
12612            mut indent_size,
12613            comment_prefix,
12614            rewrap_prefix,
12615            from_empty_selection,
12616        ) in wrap_ranges
12617        {
12618            let mut start_row = wrap_range.start.row;
12619            let mut end_row = wrap_range.end.row;
12620
12621            // Skip selections that overlap with a range that has already been rewrapped.
12622            let selection_range = start_row..end_row;
12623            if rewrapped_row_ranges
12624                .iter()
12625                .any(|range| range.overlaps(&selection_range))
12626            {
12627                continue;
12628            }
12629
12630            let tab_size = language_settings.tab_size;
12631
12632            let (line_prefix, inside_comment) = match &comment_prefix {
12633                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12634                    (Some(prefix.as_str()), true)
12635                }
12636                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12637                    (Some(prefix.as_ref()), true)
12638                }
12639                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12640                    start: _,
12641                    end: _,
12642                    prefix,
12643                    tab_size,
12644                })) => {
12645                    indent_size.len += tab_size;
12646                    (Some(prefix.as_ref()), true)
12647                }
12648                None => (None, false),
12649            };
12650            let indent_prefix = indent_size.chars().collect::<String>();
12651            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12652
12653            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12654                RewrapBehavior::InComments => inside_comment,
12655                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12656                RewrapBehavior::Anywhere => true,
12657            };
12658
12659            let should_rewrap = options.override_language_settings
12660                || allow_rewrap_based_on_language
12661                || self.hard_wrap.is_some();
12662            if !should_rewrap {
12663                continue;
12664            }
12665
12666            if from_empty_selection {
12667                'expand_upwards: while start_row > 0 {
12668                    let prev_row = start_row - 1;
12669                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12670                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12671                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12672                    {
12673                        start_row = prev_row;
12674                    } else {
12675                        break 'expand_upwards;
12676                    }
12677                }
12678
12679                'expand_downwards: while end_row < buffer.max_point().row {
12680                    let next_row = end_row + 1;
12681                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12682                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12683                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12684                    {
12685                        end_row = next_row;
12686                    } else {
12687                        break 'expand_downwards;
12688                    }
12689                }
12690            }
12691
12692            let start = Point::new(start_row, 0);
12693            let start_offset = ToOffset::to_offset(&start, &buffer);
12694            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12695            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12696            let mut first_line_delimiter = None;
12697            let mut last_line_delimiter = None;
12698            let Some(lines_without_prefixes) = selection_text
12699                .lines()
12700                .enumerate()
12701                .map(|(ix, line)| {
12702                    let line_trimmed = line.trim_start();
12703                    if rewrap_prefix.is_some() && ix > 0 {
12704                        Ok(line_trimmed)
12705                    } else if let Some(
12706                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12707                            start,
12708                            prefix,
12709                            end,
12710                            tab_size,
12711                        })
12712                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12713                            start,
12714                            prefix,
12715                            end,
12716                            tab_size,
12717                        }),
12718                    ) = &comment_prefix
12719                    {
12720                        let line_trimmed = line_trimmed
12721                            .strip_prefix(start.as_ref())
12722                            .map(|s| {
12723                                let mut indent_size = indent_size;
12724                                indent_size.len -= tab_size;
12725                                let indent_prefix: String = indent_size.chars().collect();
12726                                first_line_delimiter = Some((indent_prefix, start));
12727                                s.trim_start()
12728                            })
12729                            .unwrap_or(line_trimmed);
12730                        let line_trimmed = line_trimmed
12731                            .strip_suffix(end.as_ref())
12732                            .map(|s| {
12733                                last_line_delimiter = Some(end);
12734                                s.trim_end()
12735                            })
12736                            .unwrap_or(line_trimmed);
12737                        let line_trimmed = line_trimmed
12738                            .strip_prefix(prefix.as_ref())
12739                            .unwrap_or(line_trimmed);
12740                        Ok(line_trimmed)
12741                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12742                        line_trimmed.strip_prefix(prefix).with_context(|| {
12743                            format!("line did not start with prefix {prefix:?}: {line:?}")
12744                        })
12745                    } else {
12746                        line_trimmed
12747                            .strip_prefix(&line_prefix.trim_start())
12748                            .with_context(|| {
12749                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12750                            })
12751                    }
12752                })
12753                .collect::<Result<Vec<_>, _>>()
12754                .log_err()
12755            else {
12756                continue;
12757            };
12758
12759            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12760                buffer
12761                    .language_settings_at(Point::new(start_row, 0), cx)
12762                    .preferred_line_length as usize
12763            });
12764
12765            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12766                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12767            } else {
12768                line_prefix.clone()
12769            };
12770
12771            let wrapped_text = {
12772                let mut wrapped_text = wrap_with_prefix(
12773                    line_prefix,
12774                    subsequent_lines_prefix,
12775                    lines_without_prefixes.join("\n"),
12776                    wrap_column,
12777                    tab_size,
12778                    options.preserve_existing_whitespace,
12779                );
12780
12781                if let Some((indent, delimiter)) = first_line_delimiter {
12782                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12783                }
12784                if let Some(last_line) = last_line_delimiter {
12785                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12786                }
12787
12788                wrapped_text
12789            };
12790
12791            // TODO: should always use char-based diff while still supporting cursor behavior that
12792            // matches vim.
12793            let mut diff_options = DiffOptions::default();
12794            if options.override_language_settings {
12795                diff_options.max_word_diff_len = 0;
12796                diff_options.max_word_diff_line_count = 0;
12797            } else {
12798                diff_options.max_word_diff_len = usize::MAX;
12799                diff_options.max_word_diff_line_count = usize::MAX;
12800            }
12801
12802            for (old_range, new_text) in
12803                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12804            {
12805                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12806                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12807                edits.push((edit_start..edit_end, new_text));
12808            }
12809
12810            rewrapped_row_ranges.push(start_row..=end_row);
12811        }
12812
12813        self.buffer
12814            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12815    }
12816
12817    pub fn cut_common(
12818        &mut self,
12819        cut_no_selection_line: bool,
12820        window: &mut Window,
12821        cx: &mut Context<Self>,
12822    ) -> ClipboardItem {
12823        let mut text = String::new();
12824        let buffer = self.buffer.read(cx).snapshot(cx);
12825        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12826        let mut clipboard_selections = Vec::with_capacity(selections.len());
12827        {
12828            let max_point = buffer.max_point();
12829            let mut is_first = true;
12830            let mut prev_selection_was_entire_line = false;
12831            for selection in &mut selections {
12832                let is_entire_line =
12833                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12834                if is_entire_line {
12835                    selection.start = Point::new(selection.start.row, 0);
12836                    if !selection.is_empty() && selection.end.column == 0 {
12837                        selection.end = cmp::min(max_point, selection.end);
12838                    } else {
12839                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12840                    }
12841                    selection.goal = SelectionGoal::None;
12842                }
12843                if is_first {
12844                    is_first = false;
12845                } else if !prev_selection_was_entire_line {
12846                    text += "\n";
12847                }
12848                prev_selection_was_entire_line = is_entire_line;
12849                let mut len = 0;
12850                for chunk in buffer.text_for_range(selection.start..selection.end) {
12851                    text.push_str(chunk);
12852                    len += chunk.len();
12853                }
12854
12855                clipboard_selections.push(ClipboardSelection::for_buffer(
12856                    len,
12857                    is_entire_line,
12858                    selection.range(),
12859                    &buffer,
12860                    self.project.as_ref(),
12861                    cx,
12862                ));
12863            }
12864        }
12865
12866        self.transact(window, cx, |this, window, cx| {
12867            this.change_selections(Default::default(), window, cx, |s| {
12868                s.select(selections);
12869            });
12870            this.insert("", window, cx);
12871        });
12872        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12873    }
12874
12875    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12876        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12877        let item = self.cut_common(true, window, cx);
12878        cx.write_to_clipboard(item);
12879    }
12880
12881    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12882        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12883        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12884            s.move_with(|snapshot, sel| {
12885                if sel.is_empty() {
12886                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12887                }
12888                if sel.is_empty() {
12889                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12890                }
12891            });
12892        });
12893        let item = self.cut_common(false, window, cx);
12894        cx.set_global(KillRing(item))
12895    }
12896
12897    pub fn kill_ring_yank(
12898        &mut self,
12899        _: &KillRingYank,
12900        window: &mut Window,
12901        cx: &mut Context<Self>,
12902    ) {
12903        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12904        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12905            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12906                (kill_ring.text().to_string(), kill_ring.metadata_json())
12907            } else {
12908                return;
12909            }
12910        } else {
12911            return;
12912        };
12913        self.do_paste(&text, metadata, false, window, cx);
12914    }
12915
12916    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12917        self.do_copy(true, cx);
12918    }
12919
12920    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12921        self.do_copy(false, cx);
12922    }
12923
12924    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12925        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12926        let buffer = self.buffer.read(cx).read(cx);
12927        let mut text = String::new();
12928
12929        let mut clipboard_selections = Vec::with_capacity(selections.len());
12930        {
12931            let max_point = buffer.max_point();
12932            let mut is_first = true;
12933            let mut prev_selection_was_entire_line = false;
12934            for selection in &selections {
12935                let mut start = selection.start;
12936                let mut end = selection.end;
12937                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12938                let mut add_trailing_newline = false;
12939                if is_entire_line {
12940                    start = Point::new(start.row, 0);
12941                    let next_line_start = Point::new(end.row + 1, 0);
12942                    if next_line_start <= max_point {
12943                        end = next_line_start;
12944                    } else {
12945                        // We're on the last line without a trailing newline.
12946                        // Copy to the end of the line and add a newline afterwards.
12947                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12948                        add_trailing_newline = true;
12949                    }
12950                }
12951
12952                let mut trimmed_selections = Vec::new();
12953                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12954                    let row = MultiBufferRow(start.row);
12955                    let first_indent = buffer.indent_size_for_line(row);
12956                    if first_indent.len == 0 || start.column > first_indent.len {
12957                        trimmed_selections.push(start..end);
12958                    } else {
12959                        trimmed_selections.push(
12960                            Point::new(row.0, first_indent.len)
12961                                ..Point::new(row.0, buffer.line_len(row)),
12962                        );
12963                        for row in start.row + 1..=end.row {
12964                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12965                            if row == end.row {
12966                                line_len = end.column;
12967                            }
12968                            if line_len == 0 {
12969                                trimmed_selections
12970                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12971                                continue;
12972                            }
12973                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12974                            if row_indent_size.len >= first_indent.len {
12975                                trimmed_selections.push(
12976                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12977                                );
12978                            } else {
12979                                trimmed_selections.clear();
12980                                trimmed_selections.push(start..end);
12981                                break;
12982                            }
12983                        }
12984                    }
12985                } else {
12986                    trimmed_selections.push(start..end);
12987                }
12988
12989                for trimmed_range in trimmed_selections {
12990                    if is_first {
12991                        is_first = false;
12992                    } else if !prev_selection_was_entire_line {
12993                        text += "\n";
12994                    }
12995                    prev_selection_was_entire_line = is_entire_line;
12996                    let mut len = 0;
12997                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12998                        text.push_str(chunk);
12999                        len += chunk.len();
13000                    }
13001                    if add_trailing_newline {
13002                        text.push('\n');
13003                        len += 1;
13004                    }
13005                    clipboard_selections.push(ClipboardSelection::for_buffer(
13006                        len,
13007                        is_entire_line,
13008                        trimmed_range,
13009                        &buffer,
13010                        self.project.as_ref(),
13011                        cx,
13012                    ));
13013                }
13014            }
13015        }
13016
13017        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13018            text,
13019            clipboard_selections,
13020        ));
13021    }
13022
13023    pub fn do_paste(
13024        &mut self,
13025        text: &String,
13026        clipboard_selections: Option<Vec<ClipboardSelection>>,
13027        handle_entire_lines: bool,
13028        window: &mut Window,
13029        cx: &mut Context<Self>,
13030    ) {
13031        if self.read_only(cx) {
13032            return;
13033        }
13034
13035        let clipboard_text = Cow::Borrowed(text.as_str());
13036
13037        self.transact(window, cx, |this, window, cx| {
13038            let had_active_edit_prediction = this.has_active_edit_prediction();
13039            let display_map = this.display_snapshot(cx);
13040            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13041            let cursor_offset = this
13042                .selections
13043                .last::<MultiBufferOffset>(&display_map)
13044                .head();
13045
13046            if let Some(mut clipboard_selections) = clipboard_selections {
13047                let all_selections_were_entire_line =
13048                    clipboard_selections.iter().all(|s| s.is_entire_line);
13049                let first_selection_indent_column =
13050                    clipboard_selections.first().map(|s| s.first_line_indent);
13051                if clipboard_selections.len() != old_selections.len() {
13052                    clipboard_selections.drain(..);
13053                }
13054                let mut auto_indent_on_paste = true;
13055
13056                this.buffer.update(cx, |buffer, cx| {
13057                    let snapshot = buffer.read(cx);
13058                    auto_indent_on_paste = snapshot
13059                        .language_settings_at(cursor_offset, cx)
13060                        .auto_indent_on_paste;
13061
13062                    let mut start_offset = 0;
13063                    let mut edits = Vec::new();
13064                    let mut original_indent_columns = Vec::new();
13065                    for (ix, selection) in old_selections.iter().enumerate() {
13066                        let to_insert;
13067                        let entire_line;
13068                        let original_indent_column;
13069                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13070                            let end_offset = start_offset + clipboard_selection.len;
13071                            to_insert = &clipboard_text[start_offset..end_offset];
13072                            entire_line = clipboard_selection.is_entire_line;
13073                            start_offset = if entire_line {
13074                                end_offset
13075                            } else {
13076                                end_offset + 1
13077                            };
13078                            original_indent_column = Some(clipboard_selection.first_line_indent);
13079                        } else {
13080                            to_insert = &*clipboard_text;
13081                            entire_line = all_selections_were_entire_line;
13082                            original_indent_column = first_selection_indent_column
13083                        }
13084
13085                        let (range, to_insert) =
13086                            if selection.is_empty() && handle_entire_lines && entire_line {
13087                                // If the corresponding selection was empty when this slice of the
13088                                // clipboard text was written, then the entire line containing the
13089                                // selection was copied. If this selection is also currently empty,
13090                                // then paste the line before the current line of the buffer.
13091                                let column = selection.start.to_point(&snapshot).column as usize;
13092                                let line_start = selection.start - column;
13093                                (line_start..line_start, Cow::Borrowed(to_insert))
13094                            } else {
13095                                let language = snapshot.language_at(selection.head());
13096                                let range = selection.range();
13097                                if let Some(language) = language
13098                                    && language.name() == "Markdown".into()
13099                                {
13100                                    edit_for_markdown_paste(
13101                                        &snapshot,
13102                                        range,
13103                                        to_insert,
13104                                        url::Url::parse(to_insert).ok(),
13105                                    )
13106                                } else {
13107                                    (range, Cow::Borrowed(to_insert))
13108                                }
13109                            };
13110
13111                        edits.push((range, to_insert));
13112                        original_indent_columns.push(original_indent_column);
13113                    }
13114                    drop(snapshot);
13115
13116                    buffer.edit(
13117                        edits,
13118                        if auto_indent_on_paste {
13119                            Some(AutoindentMode::Block {
13120                                original_indent_columns,
13121                            })
13122                        } else {
13123                            None
13124                        },
13125                        cx,
13126                    );
13127                });
13128
13129                let selections = this
13130                    .selections
13131                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13132                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13133            } else {
13134                let url = url::Url::parse(&clipboard_text).ok();
13135
13136                let auto_indent_mode = if !clipboard_text.is_empty() {
13137                    Some(AutoindentMode::Block {
13138                        original_indent_columns: Vec::new(),
13139                    })
13140                } else {
13141                    None
13142                };
13143
13144                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13145                    let snapshot = buffer.snapshot(cx);
13146
13147                    let anchors = old_selections
13148                        .iter()
13149                        .map(|s| {
13150                            let anchor = snapshot.anchor_after(s.head());
13151                            s.map(|_| anchor)
13152                        })
13153                        .collect::<Vec<_>>();
13154
13155                    let mut edits = Vec::new();
13156
13157                    for selection in old_selections.iter() {
13158                        let language = snapshot.language_at(selection.head());
13159                        let range = selection.range();
13160
13161                        let (edit_range, edit_text) = if let Some(language) = language
13162                            && language.name() == "Markdown".into()
13163                        {
13164                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13165                        } else {
13166                            (range, clipboard_text.clone())
13167                        };
13168
13169                        edits.push((edit_range, edit_text));
13170                    }
13171
13172                    drop(snapshot);
13173                    buffer.edit(edits, auto_indent_mode, cx);
13174
13175                    anchors
13176                });
13177
13178                this.change_selections(Default::default(), window, cx, |s| {
13179                    s.select_anchors(selection_anchors);
13180                });
13181            }
13182
13183            //   🤔                 |    ..     | show_in_menu |
13184            // | ..                  |   true        true
13185            // | had_edit_prediction |   false       true
13186
13187            let trigger_in_words =
13188                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13189
13190            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13191        });
13192    }
13193
13194    pub fn diff_clipboard_with_selection(
13195        &mut self,
13196        _: &DiffClipboardWithSelection,
13197        window: &mut Window,
13198        cx: &mut Context<Self>,
13199    ) {
13200        let selections = self
13201            .selections
13202            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13203
13204        if selections.is_empty() {
13205            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13206            return;
13207        };
13208
13209        let clipboard_text = match cx.read_from_clipboard() {
13210            Some(item) => match item.entries().first() {
13211                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13212                _ => None,
13213            },
13214            None => None,
13215        };
13216
13217        let Some(clipboard_text) = clipboard_text else {
13218            log::warn!("Clipboard doesn't contain text.");
13219            return;
13220        };
13221
13222        window.dispatch_action(
13223            Box::new(DiffClipboardWithSelectionData {
13224                clipboard_text,
13225                editor: cx.entity(),
13226            }),
13227            cx,
13228        );
13229    }
13230
13231    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13232        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13233        if let Some(item) = cx.read_from_clipboard() {
13234            let entries = item.entries();
13235
13236            match entries.first() {
13237                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13238                // of all the pasted entries.
13239                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13240                    .do_paste(
13241                        clipboard_string.text(),
13242                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13243                        true,
13244                        window,
13245                        cx,
13246                    ),
13247                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13248            }
13249        }
13250    }
13251
13252    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13253        if self.read_only(cx) {
13254            return;
13255        }
13256
13257        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13258
13259        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13260            if let Some((selections, _)) =
13261                self.selection_history.transaction(transaction_id).cloned()
13262            {
13263                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13264                    s.select_anchors(selections.to_vec());
13265                });
13266            } else {
13267                log::error!(
13268                    "No entry in selection_history found for undo. \
13269                     This may correspond to a bug where undo does not update the selection. \
13270                     If this is occurring, please add details to \
13271                     https://github.com/zed-industries/zed/issues/22692"
13272                );
13273            }
13274            self.request_autoscroll(Autoscroll::fit(), cx);
13275            self.unmark_text(window, cx);
13276            self.refresh_edit_prediction(true, false, window, cx);
13277            cx.emit(EditorEvent::Edited { transaction_id });
13278            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13279        }
13280    }
13281
13282    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13283        if self.read_only(cx) {
13284            return;
13285        }
13286
13287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13288
13289        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13290            if let Some((_, Some(selections))) =
13291                self.selection_history.transaction(transaction_id).cloned()
13292            {
13293                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13294                    s.select_anchors(selections.to_vec());
13295                });
13296            } else {
13297                log::error!(
13298                    "No entry in selection_history found for redo. \
13299                     This may correspond to a bug where undo does not update the selection. \
13300                     If this is occurring, please add details to \
13301                     https://github.com/zed-industries/zed/issues/22692"
13302                );
13303            }
13304            self.request_autoscroll(Autoscroll::fit(), cx);
13305            self.unmark_text(window, cx);
13306            self.refresh_edit_prediction(true, false, window, cx);
13307            cx.emit(EditorEvent::Edited { transaction_id });
13308        }
13309    }
13310
13311    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13312        self.buffer
13313            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13314    }
13315
13316    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13317        self.buffer
13318            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13319    }
13320
13321    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13322        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13323        self.change_selections(Default::default(), window, cx, |s| {
13324            s.move_with(|map, selection| {
13325                let cursor = if selection.is_empty() {
13326                    movement::left(map, selection.start)
13327                } else {
13328                    selection.start
13329                };
13330                selection.collapse_to(cursor, SelectionGoal::None);
13331            });
13332        })
13333    }
13334
13335    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13337        self.change_selections(Default::default(), window, cx, |s| {
13338            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13339        })
13340    }
13341
13342    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13343        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13344        self.change_selections(Default::default(), window, cx, |s| {
13345            s.move_with(|map, selection| {
13346                let cursor = if selection.is_empty() {
13347                    movement::right(map, selection.end)
13348                } else {
13349                    selection.end
13350                };
13351                selection.collapse_to(cursor, SelectionGoal::None)
13352            });
13353        })
13354    }
13355
13356    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13357        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13358        self.change_selections(Default::default(), window, cx, |s| {
13359            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13360        });
13361    }
13362
13363    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13364        if self.take_rename(true, window, cx).is_some() {
13365            return;
13366        }
13367
13368        if self.mode.is_single_line() {
13369            cx.propagate();
13370            return;
13371        }
13372
13373        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13374
13375        let text_layout_details = &self.text_layout_details(window);
13376        let selection_count = self.selections.count();
13377        let first_selection = self.selections.first_anchor();
13378
13379        self.change_selections(Default::default(), window, cx, |s| {
13380            s.move_with(|map, selection| {
13381                if !selection.is_empty() {
13382                    selection.goal = SelectionGoal::None;
13383                }
13384                let (cursor, goal) = movement::up(
13385                    map,
13386                    selection.start,
13387                    selection.goal,
13388                    false,
13389                    text_layout_details,
13390                );
13391                selection.collapse_to(cursor, goal);
13392            });
13393        });
13394
13395        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13396        {
13397            cx.propagate();
13398        }
13399    }
13400
13401    pub fn move_up_by_lines(
13402        &mut self,
13403        action: &MoveUpByLines,
13404        window: &mut Window,
13405        cx: &mut Context<Self>,
13406    ) {
13407        if self.take_rename(true, window, cx).is_some() {
13408            return;
13409        }
13410
13411        if self.mode.is_single_line() {
13412            cx.propagate();
13413            return;
13414        }
13415
13416        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13417
13418        let text_layout_details = &self.text_layout_details(window);
13419
13420        self.change_selections(Default::default(), window, cx, |s| {
13421            s.move_with(|map, selection| {
13422                if !selection.is_empty() {
13423                    selection.goal = SelectionGoal::None;
13424                }
13425                let (cursor, goal) = movement::up_by_rows(
13426                    map,
13427                    selection.start,
13428                    action.lines,
13429                    selection.goal,
13430                    false,
13431                    text_layout_details,
13432                );
13433                selection.collapse_to(cursor, goal);
13434            });
13435        })
13436    }
13437
13438    pub fn move_down_by_lines(
13439        &mut self,
13440        action: &MoveDownByLines,
13441        window: &mut Window,
13442        cx: &mut Context<Self>,
13443    ) {
13444        if self.take_rename(true, window, cx).is_some() {
13445            return;
13446        }
13447
13448        if self.mode.is_single_line() {
13449            cx.propagate();
13450            return;
13451        }
13452
13453        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13454
13455        let text_layout_details = &self.text_layout_details(window);
13456
13457        self.change_selections(Default::default(), window, cx, |s| {
13458            s.move_with(|map, selection| {
13459                if !selection.is_empty() {
13460                    selection.goal = SelectionGoal::None;
13461                }
13462                let (cursor, goal) = movement::down_by_rows(
13463                    map,
13464                    selection.start,
13465                    action.lines,
13466                    selection.goal,
13467                    false,
13468                    text_layout_details,
13469                );
13470                selection.collapse_to(cursor, goal);
13471            });
13472        })
13473    }
13474
13475    pub fn select_down_by_lines(
13476        &mut self,
13477        action: &SelectDownByLines,
13478        window: &mut Window,
13479        cx: &mut Context<Self>,
13480    ) {
13481        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13482        let text_layout_details = &self.text_layout_details(window);
13483        self.change_selections(Default::default(), window, cx, |s| {
13484            s.move_heads_with(|map, head, goal| {
13485                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13486            })
13487        })
13488    }
13489
13490    pub fn select_up_by_lines(
13491        &mut self,
13492        action: &SelectUpByLines,
13493        window: &mut Window,
13494        cx: &mut Context<Self>,
13495    ) {
13496        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13497        let text_layout_details = &self.text_layout_details(window);
13498        self.change_selections(Default::default(), window, cx, |s| {
13499            s.move_heads_with(|map, head, goal| {
13500                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13501            })
13502        })
13503    }
13504
13505    pub fn select_page_up(
13506        &mut self,
13507        _: &SelectPageUp,
13508        window: &mut Window,
13509        cx: &mut Context<Self>,
13510    ) {
13511        let Some(row_count) = self.visible_row_count() else {
13512            return;
13513        };
13514
13515        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13516
13517        let text_layout_details = &self.text_layout_details(window);
13518
13519        self.change_selections(Default::default(), window, cx, |s| {
13520            s.move_heads_with(|map, head, goal| {
13521                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13522            })
13523        })
13524    }
13525
13526    pub fn move_page_up(
13527        &mut self,
13528        action: &MovePageUp,
13529        window: &mut Window,
13530        cx: &mut Context<Self>,
13531    ) {
13532        if self.take_rename(true, window, cx).is_some() {
13533            return;
13534        }
13535
13536        if self
13537            .context_menu
13538            .borrow_mut()
13539            .as_mut()
13540            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13541            .unwrap_or(false)
13542        {
13543            return;
13544        }
13545
13546        if matches!(self.mode, EditorMode::SingleLine) {
13547            cx.propagate();
13548            return;
13549        }
13550
13551        let Some(row_count) = self.visible_row_count() else {
13552            return;
13553        };
13554
13555        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13556
13557        let effects = if action.center_cursor {
13558            SelectionEffects::scroll(Autoscroll::center())
13559        } else {
13560            SelectionEffects::default()
13561        };
13562
13563        let text_layout_details = &self.text_layout_details(window);
13564
13565        self.change_selections(effects, window, cx, |s| {
13566            s.move_with(|map, selection| {
13567                if !selection.is_empty() {
13568                    selection.goal = SelectionGoal::None;
13569                }
13570                let (cursor, goal) = movement::up_by_rows(
13571                    map,
13572                    selection.end,
13573                    row_count,
13574                    selection.goal,
13575                    false,
13576                    text_layout_details,
13577                );
13578                selection.collapse_to(cursor, goal);
13579            });
13580        });
13581    }
13582
13583    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13585        let text_layout_details = &self.text_layout_details(window);
13586        self.change_selections(Default::default(), window, cx, |s| {
13587            s.move_heads_with(|map, head, goal| {
13588                movement::up(map, head, goal, false, text_layout_details)
13589            })
13590        })
13591    }
13592
13593    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13594        self.take_rename(true, window, cx);
13595
13596        if self.mode.is_single_line() {
13597            cx.propagate();
13598            return;
13599        }
13600
13601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13602
13603        let text_layout_details = &self.text_layout_details(window);
13604        let selection_count = self.selections.count();
13605        let first_selection = self.selections.first_anchor();
13606
13607        self.change_selections(Default::default(), window, cx, |s| {
13608            s.move_with(|map, selection| {
13609                if !selection.is_empty() {
13610                    selection.goal = SelectionGoal::None;
13611                }
13612                let (cursor, goal) = movement::down(
13613                    map,
13614                    selection.end,
13615                    selection.goal,
13616                    false,
13617                    text_layout_details,
13618                );
13619                selection.collapse_to(cursor, goal);
13620            });
13621        });
13622
13623        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13624        {
13625            cx.propagate();
13626        }
13627    }
13628
13629    pub fn select_page_down(
13630        &mut self,
13631        _: &SelectPageDown,
13632        window: &mut Window,
13633        cx: &mut Context<Self>,
13634    ) {
13635        let Some(row_count) = self.visible_row_count() else {
13636            return;
13637        };
13638
13639        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13640
13641        let text_layout_details = &self.text_layout_details(window);
13642
13643        self.change_selections(Default::default(), window, cx, |s| {
13644            s.move_heads_with(|map, head, goal| {
13645                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13646            })
13647        })
13648    }
13649
13650    pub fn move_page_down(
13651        &mut self,
13652        action: &MovePageDown,
13653        window: &mut Window,
13654        cx: &mut Context<Self>,
13655    ) {
13656        if self.take_rename(true, window, cx).is_some() {
13657            return;
13658        }
13659
13660        if self
13661            .context_menu
13662            .borrow_mut()
13663            .as_mut()
13664            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13665            .unwrap_or(false)
13666        {
13667            return;
13668        }
13669
13670        if matches!(self.mode, EditorMode::SingleLine) {
13671            cx.propagate();
13672            return;
13673        }
13674
13675        let Some(row_count) = self.visible_row_count() else {
13676            return;
13677        };
13678
13679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13680
13681        let effects = if action.center_cursor {
13682            SelectionEffects::scroll(Autoscroll::center())
13683        } else {
13684            SelectionEffects::default()
13685        };
13686
13687        let text_layout_details = &self.text_layout_details(window);
13688        self.change_selections(effects, window, cx, |s| {
13689            s.move_with(|map, selection| {
13690                if !selection.is_empty() {
13691                    selection.goal = SelectionGoal::None;
13692                }
13693                let (cursor, goal) = movement::down_by_rows(
13694                    map,
13695                    selection.end,
13696                    row_count,
13697                    selection.goal,
13698                    false,
13699                    text_layout_details,
13700                );
13701                selection.collapse_to(cursor, goal);
13702            });
13703        });
13704    }
13705
13706    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13707        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13708        let text_layout_details = &self.text_layout_details(window);
13709        self.change_selections(Default::default(), window, cx, |s| {
13710            s.move_heads_with(|map, head, goal| {
13711                movement::down(map, head, goal, false, text_layout_details)
13712            })
13713        });
13714    }
13715
13716    pub fn context_menu_first(
13717        &mut self,
13718        _: &ContextMenuFirst,
13719        window: &mut Window,
13720        cx: &mut Context<Self>,
13721    ) {
13722        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13723            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13724        }
13725    }
13726
13727    pub fn context_menu_prev(
13728        &mut self,
13729        _: &ContextMenuPrevious,
13730        window: &mut Window,
13731        cx: &mut Context<Self>,
13732    ) {
13733        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13734            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13735        }
13736    }
13737
13738    pub fn context_menu_next(
13739        &mut self,
13740        _: &ContextMenuNext,
13741        window: &mut Window,
13742        cx: &mut Context<Self>,
13743    ) {
13744        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13745            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13746        }
13747    }
13748
13749    pub fn context_menu_last(
13750        &mut self,
13751        _: &ContextMenuLast,
13752        window: &mut Window,
13753        cx: &mut Context<Self>,
13754    ) {
13755        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13756            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13757        }
13758    }
13759
13760    pub fn signature_help_prev(
13761        &mut self,
13762        _: &SignatureHelpPrevious,
13763        _: &mut Window,
13764        cx: &mut Context<Self>,
13765    ) {
13766        if let Some(popover) = self.signature_help_state.popover_mut() {
13767            if popover.current_signature == 0 {
13768                popover.current_signature = popover.signatures.len() - 1;
13769            } else {
13770                popover.current_signature -= 1;
13771            }
13772            cx.notify();
13773        }
13774    }
13775
13776    pub fn signature_help_next(
13777        &mut self,
13778        _: &SignatureHelpNext,
13779        _: &mut Window,
13780        cx: &mut Context<Self>,
13781    ) {
13782        if let Some(popover) = self.signature_help_state.popover_mut() {
13783            if popover.current_signature + 1 == popover.signatures.len() {
13784                popover.current_signature = 0;
13785            } else {
13786                popover.current_signature += 1;
13787            }
13788            cx.notify();
13789        }
13790    }
13791
13792    pub fn move_to_previous_word_start(
13793        &mut self,
13794        _: &MoveToPreviousWordStart,
13795        window: &mut Window,
13796        cx: &mut Context<Self>,
13797    ) {
13798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13799        self.change_selections(Default::default(), window, cx, |s| {
13800            s.move_cursors_with(|map, head, _| {
13801                (
13802                    movement::previous_word_start(map, head),
13803                    SelectionGoal::None,
13804                )
13805            });
13806        })
13807    }
13808
13809    pub fn move_to_previous_subword_start(
13810        &mut self,
13811        _: &MoveToPreviousSubwordStart,
13812        window: &mut Window,
13813        cx: &mut Context<Self>,
13814    ) {
13815        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13816        self.change_selections(Default::default(), window, cx, |s| {
13817            s.move_cursors_with(|map, head, _| {
13818                (
13819                    movement::previous_subword_start(map, head),
13820                    SelectionGoal::None,
13821                )
13822            });
13823        })
13824    }
13825
13826    pub fn select_to_previous_word_start(
13827        &mut self,
13828        _: &SelectToPreviousWordStart,
13829        window: &mut Window,
13830        cx: &mut Context<Self>,
13831    ) {
13832        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13833        self.change_selections(Default::default(), window, cx, |s| {
13834            s.move_heads_with(|map, head, _| {
13835                (
13836                    movement::previous_word_start(map, head),
13837                    SelectionGoal::None,
13838                )
13839            });
13840        })
13841    }
13842
13843    pub fn select_to_previous_subword_start(
13844        &mut self,
13845        _: &SelectToPreviousSubwordStart,
13846        window: &mut Window,
13847        cx: &mut Context<Self>,
13848    ) {
13849        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13850        self.change_selections(Default::default(), window, cx, |s| {
13851            s.move_heads_with(|map, head, _| {
13852                (
13853                    movement::previous_subword_start(map, head),
13854                    SelectionGoal::None,
13855                )
13856            });
13857        })
13858    }
13859
13860    pub fn delete_to_previous_word_start(
13861        &mut self,
13862        action: &DeleteToPreviousWordStart,
13863        window: &mut Window,
13864        cx: &mut Context<Self>,
13865    ) {
13866        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13867        self.transact(window, cx, |this, window, cx| {
13868            this.select_autoclose_pair(window, cx);
13869            this.change_selections(Default::default(), window, cx, |s| {
13870                s.move_with(|map, selection| {
13871                    if selection.is_empty() {
13872                        let mut cursor = if action.ignore_newlines {
13873                            movement::previous_word_start(map, selection.head())
13874                        } else {
13875                            movement::previous_word_start_or_newline(map, selection.head())
13876                        };
13877                        cursor = movement::adjust_greedy_deletion(
13878                            map,
13879                            selection.head(),
13880                            cursor,
13881                            action.ignore_brackets,
13882                        );
13883                        selection.set_head(cursor, SelectionGoal::None);
13884                    }
13885                });
13886            });
13887            this.insert("", window, cx);
13888        });
13889    }
13890
13891    pub fn delete_to_previous_subword_start(
13892        &mut self,
13893        _: &DeleteToPreviousSubwordStart,
13894        window: &mut Window,
13895        cx: &mut Context<Self>,
13896    ) {
13897        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13898        self.transact(window, cx, |this, window, cx| {
13899            this.select_autoclose_pair(window, cx);
13900            this.change_selections(Default::default(), window, cx, |s| {
13901                s.move_with(|map, selection| {
13902                    if selection.is_empty() {
13903                        let mut cursor = movement::previous_subword_start(map, selection.head());
13904                        cursor =
13905                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13906                        selection.set_head(cursor, SelectionGoal::None);
13907                    }
13908                });
13909            });
13910            this.insert("", window, cx);
13911        });
13912    }
13913
13914    pub fn move_to_next_word_end(
13915        &mut self,
13916        _: &MoveToNextWordEnd,
13917        window: &mut Window,
13918        cx: &mut Context<Self>,
13919    ) {
13920        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13921        self.change_selections(Default::default(), window, cx, |s| {
13922            s.move_cursors_with(|map, head, _| {
13923                (movement::next_word_end(map, head), SelectionGoal::None)
13924            });
13925        })
13926    }
13927
13928    pub fn move_to_next_subword_end(
13929        &mut self,
13930        _: &MoveToNextSubwordEnd,
13931        window: &mut Window,
13932        cx: &mut Context<Self>,
13933    ) {
13934        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13935        self.change_selections(Default::default(), window, cx, |s| {
13936            s.move_cursors_with(|map, head, _| {
13937                (movement::next_subword_end(map, head), SelectionGoal::None)
13938            });
13939        })
13940    }
13941
13942    pub fn select_to_next_word_end(
13943        &mut self,
13944        _: &SelectToNextWordEnd,
13945        window: &mut Window,
13946        cx: &mut Context<Self>,
13947    ) {
13948        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13949        self.change_selections(Default::default(), window, cx, |s| {
13950            s.move_heads_with(|map, head, _| {
13951                (movement::next_word_end(map, head), SelectionGoal::None)
13952            });
13953        })
13954    }
13955
13956    pub fn select_to_next_subword_end(
13957        &mut self,
13958        _: &SelectToNextSubwordEnd,
13959        window: &mut Window,
13960        cx: &mut Context<Self>,
13961    ) {
13962        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13963        self.change_selections(Default::default(), window, cx, |s| {
13964            s.move_heads_with(|map, head, _| {
13965                (movement::next_subword_end(map, head), SelectionGoal::None)
13966            });
13967        })
13968    }
13969
13970    pub fn delete_to_next_word_end(
13971        &mut self,
13972        action: &DeleteToNextWordEnd,
13973        window: &mut Window,
13974        cx: &mut Context<Self>,
13975    ) {
13976        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13977        self.transact(window, cx, |this, window, cx| {
13978            this.change_selections(Default::default(), window, cx, |s| {
13979                s.move_with(|map, selection| {
13980                    if selection.is_empty() {
13981                        let mut cursor = if action.ignore_newlines {
13982                            movement::next_word_end(map, selection.head())
13983                        } else {
13984                            movement::next_word_end_or_newline(map, selection.head())
13985                        };
13986                        cursor = movement::adjust_greedy_deletion(
13987                            map,
13988                            selection.head(),
13989                            cursor,
13990                            action.ignore_brackets,
13991                        );
13992                        selection.set_head(cursor, SelectionGoal::None);
13993                    }
13994                });
13995            });
13996            this.insert("", window, cx);
13997        });
13998    }
13999
14000    pub fn delete_to_next_subword_end(
14001        &mut self,
14002        _: &DeleteToNextSubwordEnd,
14003        window: &mut Window,
14004        cx: &mut Context<Self>,
14005    ) {
14006        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14007        self.transact(window, cx, |this, window, cx| {
14008            this.change_selections(Default::default(), window, cx, |s| {
14009                s.move_with(|map, selection| {
14010                    if selection.is_empty() {
14011                        let mut cursor = movement::next_subword_end(map, selection.head());
14012                        cursor =
14013                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14014                        selection.set_head(cursor, SelectionGoal::None);
14015                    }
14016                });
14017            });
14018            this.insert("", window, cx);
14019        });
14020    }
14021
14022    pub fn move_to_beginning_of_line(
14023        &mut self,
14024        action: &MoveToBeginningOfLine,
14025        window: &mut Window,
14026        cx: &mut Context<Self>,
14027    ) {
14028        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14029        self.change_selections(Default::default(), window, cx, |s| {
14030            s.move_cursors_with(|map, head, _| {
14031                (
14032                    movement::indented_line_beginning(
14033                        map,
14034                        head,
14035                        action.stop_at_soft_wraps,
14036                        action.stop_at_indent,
14037                    ),
14038                    SelectionGoal::None,
14039                )
14040            });
14041        })
14042    }
14043
14044    pub fn select_to_beginning_of_line(
14045        &mut self,
14046        action: &SelectToBeginningOfLine,
14047        window: &mut Window,
14048        cx: &mut Context<Self>,
14049    ) {
14050        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14051        self.change_selections(Default::default(), window, cx, |s| {
14052            s.move_heads_with(|map, head, _| {
14053                (
14054                    movement::indented_line_beginning(
14055                        map,
14056                        head,
14057                        action.stop_at_soft_wraps,
14058                        action.stop_at_indent,
14059                    ),
14060                    SelectionGoal::None,
14061                )
14062            });
14063        });
14064    }
14065
14066    pub fn delete_to_beginning_of_line(
14067        &mut self,
14068        action: &DeleteToBeginningOfLine,
14069        window: &mut Window,
14070        cx: &mut Context<Self>,
14071    ) {
14072        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14073        self.transact(window, cx, |this, window, cx| {
14074            this.change_selections(Default::default(), window, cx, |s| {
14075                s.move_with(|_, selection| {
14076                    selection.reversed = true;
14077                });
14078            });
14079
14080            this.select_to_beginning_of_line(
14081                &SelectToBeginningOfLine {
14082                    stop_at_soft_wraps: false,
14083                    stop_at_indent: action.stop_at_indent,
14084                },
14085                window,
14086                cx,
14087            );
14088            this.backspace(&Backspace, window, cx);
14089        });
14090    }
14091
14092    pub fn move_to_end_of_line(
14093        &mut self,
14094        action: &MoveToEndOfLine,
14095        window: &mut Window,
14096        cx: &mut Context<Self>,
14097    ) {
14098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14099        self.change_selections(Default::default(), window, cx, |s| {
14100            s.move_cursors_with(|map, head, _| {
14101                (
14102                    movement::line_end(map, head, action.stop_at_soft_wraps),
14103                    SelectionGoal::None,
14104                )
14105            });
14106        })
14107    }
14108
14109    pub fn select_to_end_of_line(
14110        &mut self,
14111        action: &SelectToEndOfLine,
14112        window: &mut Window,
14113        cx: &mut Context<Self>,
14114    ) {
14115        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14116        self.change_selections(Default::default(), window, cx, |s| {
14117            s.move_heads_with(|map, head, _| {
14118                (
14119                    movement::line_end(map, head, action.stop_at_soft_wraps),
14120                    SelectionGoal::None,
14121                )
14122            });
14123        })
14124    }
14125
14126    pub fn delete_to_end_of_line(
14127        &mut self,
14128        _: &DeleteToEndOfLine,
14129        window: &mut Window,
14130        cx: &mut Context<Self>,
14131    ) {
14132        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14133        self.transact(window, cx, |this, window, cx| {
14134            this.select_to_end_of_line(
14135                &SelectToEndOfLine {
14136                    stop_at_soft_wraps: false,
14137                },
14138                window,
14139                cx,
14140            );
14141            this.delete(&Delete, window, cx);
14142        });
14143    }
14144
14145    pub fn cut_to_end_of_line(
14146        &mut self,
14147        action: &CutToEndOfLine,
14148        window: &mut Window,
14149        cx: &mut Context<Self>,
14150    ) {
14151        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14152        self.transact(window, cx, |this, window, cx| {
14153            this.select_to_end_of_line(
14154                &SelectToEndOfLine {
14155                    stop_at_soft_wraps: false,
14156                },
14157                window,
14158                cx,
14159            );
14160            if !action.stop_at_newlines {
14161                this.change_selections(Default::default(), window, cx, |s| {
14162                    s.move_with(|_, sel| {
14163                        if sel.is_empty() {
14164                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14165                        }
14166                    });
14167                });
14168            }
14169            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14170            let item = this.cut_common(false, window, cx);
14171            cx.write_to_clipboard(item);
14172        });
14173    }
14174
14175    pub fn move_to_start_of_paragraph(
14176        &mut self,
14177        _: &MoveToStartOfParagraph,
14178        window: &mut Window,
14179        cx: &mut Context<Self>,
14180    ) {
14181        if matches!(self.mode, EditorMode::SingleLine) {
14182            cx.propagate();
14183            return;
14184        }
14185        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14186        self.change_selections(Default::default(), window, cx, |s| {
14187            s.move_with(|map, selection| {
14188                selection.collapse_to(
14189                    movement::start_of_paragraph(map, selection.head(), 1),
14190                    SelectionGoal::None,
14191                )
14192            });
14193        })
14194    }
14195
14196    pub fn move_to_end_of_paragraph(
14197        &mut self,
14198        _: &MoveToEndOfParagraph,
14199        window: &mut Window,
14200        cx: &mut Context<Self>,
14201    ) {
14202        if matches!(self.mode, EditorMode::SingleLine) {
14203            cx.propagate();
14204            return;
14205        }
14206        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14207        self.change_selections(Default::default(), window, cx, |s| {
14208            s.move_with(|map, selection| {
14209                selection.collapse_to(
14210                    movement::end_of_paragraph(map, selection.head(), 1),
14211                    SelectionGoal::None,
14212                )
14213            });
14214        })
14215    }
14216
14217    pub fn select_to_start_of_paragraph(
14218        &mut self,
14219        _: &SelectToStartOfParagraph,
14220        window: &mut Window,
14221        cx: &mut Context<Self>,
14222    ) {
14223        if matches!(self.mode, EditorMode::SingleLine) {
14224            cx.propagate();
14225            return;
14226        }
14227        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14228        self.change_selections(Default::default(), window, cx, |s| {
14229            s.move_heads_with(|map, head, _| {
14230                (
14231                    movement::start_of_paragraph(map, head, 1),
14232                    SelectionGoal::None,
14233                )
14234            });
14235        })
14236    }
14237
14238    pub fn select_to_end_of_paragraph(
14239        &mut self,
14240        _: &SelectToEndOfParagraph,
14241        window: &mut Window,
14242        cx: &mut Context<Self>,
14243    ) {
14244        if matches!(self.mode, EditorMode::SingleLine) {
14245            cx.propagate();
14246            return;
14247        }
14248        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14249        self.change_selections(Default::default(), window, cx, |s| {
14250            s.move_heads_with(|map, head, _| {
14251                (
14252                    movement::end_of_paragraph(map, head, 1),
14253                    SelectionGoal::None,
14254                )
14255            });
14256        })
14257    }
14258
14259    pub fn move_to_start_of_excerpt(
14260        &mut self,
14261        _: &MoveToStartOfExcerpt,
14262        window: &mut Window,
14263        cx: &mut Context<Self>,
14264    ) {
14265        if matches!(self.mode, EditorMode::SingleLine) {
14266            cx.propagate();
14267            return;
14268        }
14269        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14270        self.change_selections(Default::default(), window, cx, |s| {
14271            s.move_with(|map, selection| {
14272                selection.collapse_to(
14273                    movement::start_of_excerpt(
14274                        map,
14275                        selection.head(),
14276                        workspace::searchable::Direction::Prev,
14277                    ),
14278                    SelectionGoal::None,
14279                )
14280            });
14281        })
14282    }
14283
14284    pub fn move_to_start_of_next_excerpt(
14285        &mut self,
14286        _: &MoveToStartOfNextExcerpt,
14287        window: &mut Window,
14288        cx: &mut Context<Self>,
14289    ) {
14290        if matches!(self.mode, EditorMode::SingleLine) {
14291            cx.propagate();
14292            return;
14293        }
14294
14295        self.change_selections(Default::default(), window, cx, |s| {
14296            s.move_with(|map, selection| {
14297                selection.collapse_to(
14298                    movement::start_of_excerpt(
14299                        map,
14300                        selection.head(),
14301                        workspace::searchable::Direction::Next,
14302                    ),
14303                    SelectionGoal::None,
14304                )
14305            });
14306        })
14307    }
14308
14309    pub fn move_to_end_of_excerpt(
14310        &mut self,
14311        _: &MoveToEndOfExcerpt,
14312        window: &mut Window,
14313        cx: &mut Context<Self>,
14314    ) {
14315        if matches!(self.mode, EditorMode::SingleLine) {
14316            cx.propagate();
14317            return;
14318        }
14319        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14320        self.change_selections(Default::default(), window, cx, |s| {
14321            s.move_with(|map, selection| {
14322                selection.collapse_to(
14323                    movement::end_of_excerpt(
14324                        map,
14325                        selection.head(),
14326                        workspace::searchable::Direction::Next,
14327                    ),
14328                    SelectionGoal::None,
14329                )
14330            });
14331        })
14332    }
14333
14334    pub fn move_to_end_of_previous_excerpt(
14335        &mut self,
14336        _: &MoveToEndOfPreviousExcerpt,
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_with(|map, selection| {
14347                selection.collapse_to(
14348                    movement::end_of_excerpt(
14349                        map,
14350                        selection.head(),
14351                        workspace::searchable::Direction::Prev,
14352                    ),
14353                    SelectionGoal::None,
14354                )
14355            });
14356        })
14357    }
14358
14359    pub fn select_to_start_of_excerpt(
14360        &mut self,
14361        _: &SelectToStartOfExcerpt,
14362        window: &mut Window,
14363        cx: &mut Context<Self>,
14364    ) {
14365        if matches!(self.mode, EditorMode::SingleLine) {
14366            cx.propagate();
14367            return;
14368        }
14369        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14370        self.change_selections(Default::default(), window, cx, |s| {
14371            s.move_heads_with(|map, head, _| {
14372                (
14373                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14374                    SelectionGoal::None,
14375                )
14376            });
14377        })
14378    }
14379
14380    pub fn select_to_start_of_next_excerpt(
14381        &mut self,
14382        _: &SelectToStartOfNextExcerpt,
14383        window: &mut Window,
14384        cx: &mut Context<Self>,
14385    ) {
14386        if matches!(self.mode, EditorMode::SingleLine) {
14387            cx.propagate();
14388            return;
14389        }
14390        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14391        self.change_selections(Default::default(), window, cx, |s| {
14392            s.move_heads_with(|map, head, _| {
14393                (
14394                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14395                    SelectionGoal::None,
14396                )
14397            });
14398        })
14399    }
14400
14401    pub fn select_to_end_of_excerpt(
14402        &mut self,
14403        _: &SelectToEndOfExcerpt,
14404        window: &mut Window,
14405        cx: &mut Context<Self>,
14406    ) {
14407        if matches!(self.mode, EditorMode::SingleLine) {
14408            cx.propagate();
14409            return;
14410        }
14411        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14412        self.change_selections(Default::default(), window, cx, |s| {
14413            s.move_heads_with(|map, head, _| {
14414                (
14415                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14416                    SelectionGoal::None,
14417                )
14418            });
14419        })
14420    }
14421
14422    pub fn select_to_end_of_previous_excerpt(
14423        &mut self,
14424        _: &SelectToEndOfPreviousExcerpt,
14425        window: &mut Window,
14426        cx: &mut Context<Self>,
14427    ) {
14428        if matches!(self.mode, EditorMode::SingleLine) {
14429            cx.propagate();
14430            return;
14431        }
14432        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14433        self.change_selections(Default::default(), window, cx, |s| {
14434            s.move_heads_with(|map, head, _| {
14435                (
14436                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14437                    SelectionGoal::None,
14438                )
14439            });
14440        })
14441    }
14442
14443    pub fn move_to_beginning(
14444        &mut self,
14445        _: &MoveToBeginning,
14446        window: &mut Window,
14447        cx: &mut Context<Self>,
14448    ) {
14449        if matches!(self.mode, EditorMode::SingleLine) {
14450            cx.propagate();
14451            return;
14452        }
14453        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14454        self.change_selections(Default::default(), window, cx, |s| {
14455            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14456        });
14457    }
14458
14459    pub fn select_to_beginning(
14460        &mut self,
14461        _: &SelectToBeginning,
14462        window: &mut Window,
14463        cx: &mut Context<Self>,
14464    ) {
14465        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14466        selection.set_head(Point::zero(), SelectionGoal::None);
14467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14468        self.change_selections(Default::default(), window, cx, |s| {
14469            s.select(vec![selection]);
14470        });
14471    }
14472
14473    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14474        if matches!(self.mode, EditorMode::SingleLine) {
14475            cx.propagate();
14476            return;
14477        }
14478        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14479        let cursor = self.buffer.read(cx).read(cx).len();
14480        self.change_selections(Default::default(), window, cx, |s| {
14481            s.select_ranges(vec![cursor..cursor])
14482        });
14483    }
14484
14485    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14486        self.nav_history = nav_history;
14487    }
14488
14489    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14490        self.nav_history.as_ref()
14491    }
14492
14493    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14494        self.push_to_nav_history(
14495            self.selections.newest_anchor().head(),
14496            None,
14497            false,
14498            true,
14499            cx,
14500        );
14501    }
14502
14503    fn push_to_nav_history(
14504        &mut self,
14505        cursor_anchor: Anchor,
14506        new_position: Option<Point>,
14507        is_deactivate: bool,
14508        always: bool,
14509        cx: &mut Context<Self>,
14510    ) {
14511        if let Some(nav_history) = self.nav_history.as_mut() {
14512            let buffer = self.buffer.read(cx).read(cx);
14513            let cursor_position = cursor_anchor.to_point(&buffer);
14514            let scroll_state = self.scroll_manager.anchor();
14515            let scroll_top_row = scroll_state.top_row(&buffer);
14516            drop(buffer);
14517
14518            if let Some(new_position) = new_position {
14519                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14520                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14521                    return;
14522                }
14523            }
14524
14525            nav_history.push(
14526                Some(NavigationData {
14527                    cursor_anchor,
14528                    cursor_position,
14529                    scroll_anchor: scroll_state,
14530                    scroll_top_row,
14531                }),
14532                cx,
14533            );
14534            cx.emit(EditorEvent::PushedToNavHistory {
14535                anchor: cursor_anchor,
14536                is_deactivate,
14537            })
14538        }
14539    }
14540
14541    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14542        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14543        let buffer = self.buffer.read(cx).snapshot(cx);
14544        let mut selection = self
14545            .selections
14546            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14547        selection.set_head(buffer.len(), SelectionGoal::None);
14548        self.change_selections(Default::default(), window, cx, |s| {
14549            s.select(vec![selection]);
14550        });
14551    }
14552
14553    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14554        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14555        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14556            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14557        });
14558    }
14559
14560    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14561        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14562        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14563        let mut selections = self.selections.all::<Point>(&display_map);
14564        let max_point = display_map.buffer_snapshot().max_point();
14565        for selection in &mut selections {
14566            let rows = selection.spanned_rows(true, &display_map);
14567            selection.start = Point::new(rows.start.0, 0);
14568            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14569            selection.reversed = false;
14570        }
14571        self.change_selections(Default::default(), window, cx, |s| {
14572            s.select(selections);
14573        });
14574    }
14575
14576    pub fn split_selection_into_lines(
14577        &mut self,
14578        action: &SplitSelectionIntoLines,
14579        window: &mut Window,
14580        cx: &mut Context<Self>,
14581    ) {
14582        let selections = self
14583            .selections
14584            .all::<Point>(&self.display_snapshot(cx))
14585            .into_iter()
14586            .map(|selection| selection.start..selection.end)
14587            .collect::<Vec<_>>();
14588        self.unfold_ranges(&selections, true, true, cx);
14589
14590        let mut new_selection_ranges = Vec::new();
14591        {
14592            let buffer = self.buffer.read(cx).read(cx);
14593            for selection in selections {
14594                for row in selection.start.row..selection.end.row {
14595                    let line_start = Point::new(row, 0);
14596                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14597
14598                    if action.keep_selections {
14599                        // Keep the selection range for each line
14600                        let selection_start = if row == selection.start.row {
14601                            selection.start
14602                        } else {
14603                            line_start
14604                        };
14605                        new_selection_ranges.push(selection_start..line_end);
14606                    } else {
14607                        // Collapse to cursor at end of line
14608                        new_selection_ranges.push(line_end..line_end);
14609                    }
14610                }
14611
14612                let is_multiline_selection = selection.start.row != selection.end.row;
14613                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14614                // so this action feels more ergonomic when paired with other selection operations
14615                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14616                if !should_skip_last {
14617                    if action.keep_selections {
14618                        if is_multiline_selection {
14619                            let line_start = Point::new(selection.end.row, 0);
14620                            new_selection_ranges.push(line_start..selection.end);
14621                        } else {
14622                            new_selection_ranges.push(selection.start..selection.end);
14623                        }
14624                    } else {
14625                        new_selection_ranges.push(selection.end..selection.end);
14626                    }
14627                }
14628            }
14629        }
14630        self.change_selections(Default::default(), window, cx, |s| {
14631            s.select_ranges(new_selection_ranges);
14632        });
14633    }
14634
14635    pub fn add_selection_above(
14636        &mut self,
14637        action: &AddSelectionAbove,
14638        window: &mut Window,
14639        cx: &mut Context<Self>,
14640    ) {
14641        self.add_selection(true, action.skip_soft_wrap, window, cx);
14642    }
14643
14644    pub fn add_selection_below(
14645        &mut self,
14646        action: &AddSelectionBelow,
14647        window: &mut Window,
14648        cx: &mut Context<Self>,
14649    ) {
14650        self.add_selection(false, action.skip_soft_wrap, window, cx);
14651    }
14652
14653    fn add_selection(
14654        &mut self,
14655        above: bool,
14656        skip_soft_wrap: bool,
14657        window: &mut Window,
14658        cx: &mut Context<Self>,
14659    ) {
14660        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14661
14662        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14663        let all_selections = self.selections.all::<Point>(&display_map);
14664        let text_layout_details = self.text_layout_details(window);
14665
14666        let (mut columnar_selections, new_selections_to_columnarize) = {
14667            if let Some(state) = self.add_selections_state.as_ref() {
14668                let columnar_selection_ids: HashSet<_> = state
14669                    .groups
14670                    .iter()
14671                    .flat_map(|group| group.stack.iter())
14672                    .copied()
14673                    .collect();
14674
14675                all_selections
14676                    .into_iter()
14677                    .partition(|s| columnar_selection_ids.contains(&s.id))
14678            } else {
14679                (Vec::new(), all_selections)
14680            }
14681        };
14682
14683        let mut state = self
14684            .add_selections_state
14685            .take()
14686            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14687
14688        for selection in new_selections_to_columnarize {
14689            let range = selection.display_range(&display_map).sorted();
14690            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14691            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14692            let positions = start_x.min(end_x)..start_x.max(end_x);
14693            let mut stack = Vec::new();
14694            for row in range.start.row().0..=range.end.row().0 {
14695                if let Some(selection) = self.selections.build_columnar_selection(
14696                    &display_map,
14697                    DisplayRow(row),
14698                    &positions,
14699                    selection.reversed,
14700                    &text_layout_details,
14701                ) {
14702                    stack.push(selection.id);
14703                    columnar_selections.push(selection);
14704                }
14705            }
14706            if !stack.is_empty() {
14707                if above {
14708                    stack.reverse();
14709                }
14710                state.groups.push(AddSelectionsGroup { above, stack });
14711            }
14712        }
14713
14714        let mut final_selections = Vec::new();
14715        let end_row = if above {
14716            DisplayRow(0)
14717        } else {
14718            display_map.max_point().row()
14719        };
14720
14721        let mut last_added_item_per_group = HashMap::default();
14722        for group in state.groups.iter_mut() {
14723            if let Some(last_id) = group.stack.last() {
14724                last_added_item_per_group.insert(*last_id, group);
14725            }
14726        }
14727
14728        for selection in columnar_selections {
14729            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14730                if above == group.above {
14731                    let range = selection.display_range(&display_map).sorted();
14732                    debug_assert_eq!(range.start.row(), range.end.row());
14733                    let mut row = range.start.row();
14734                    let positions =
14735                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14736                            Pixels::from(start)..Pixels::from(end)
14737                        } else {
14738                            let start_x =
14739                                display_map.x_for_display_point(range.start, &text_layout_details);
14740                            let end_x =
14741                                display_map.x_for_display_point(range.end, &text_layout_details);
14742                            start_x.min(end_x)..start_x.max(end_x)
14743                        };
14744
14745                    let mut maybe_new_selection = None;
14746                    let direction = if above { -1 } else { 1 };
14747
14748                    while row != end_row {
14749                        if skip_soft_wrap {
14750                            row = display_map
14751                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14752                                .row();
14753                        } else if above {
14754                            row.0 -= 1;
14755                        } else {
14756                            row.0 += 1;
14757                        }
14758
14759                        if let Some(new_selection) = self.selections.build_columnar_selection(
14760                            &display_map,
14761                            row,
14762                            &positions,
14763                            selection.reversed,
14764                            &text_layout_details,
14765                        ) {
14766                            maybe_new_selection = Some(new_selection);
14767                            break;
14768                        }
14769                    }
14770
14771                    if let Some(new_selection) = maybe_new_selection {
14772                        group.stack.push(new_selection.id);
14773                        if above {
14774                            final_selections.push(new_selection);
14775                            final_selections.push(selection);
14776                        } else {
14777                            final_selections.push(selection);
14778                            final_selections.push(new_selection);
14779                        }
14780                    } else {
14781                        final_selections.push(selection);
14782                    }
14783                } else {
14784                    group.stack.pop();
14785                }
14786            } else {
14787                final_selections.push(selection);
14788            }
14789        }
14790
14791        self.change_selections(Default::default(), window, cx, |s| {
14792            s.select(final_selections);
14793        });
14794
14795        let final_selection_ids: HashSet<_> = self
14796            .selections
14797            .all::<Point>(&display_map)
14798            .iter()
14799            .map(|s| s.id)
14800            .collect();
14801        state.groups.retain_mut(|group| {
14802            // selections might get merged above so we remove invalid items from stacks
14803            group.stack.retain(|id| final_selection_ids.contains(id));
14804
14805            // single selection in stack can be treated as initial state
14806            group.stack.len() > 1
14807        });
14808
14809        if !state.groups.is_empty() {
14810            self.add_selections_state = Some(state);
14811        }
14812    }
14813
14814    pub fn insert_snippet_at_selections(
14815        &mut self,
14816        action: &InsertSnippet,
14817        window: &mut Window,
14818        cx: &mut Context<Self>,
14819    ) {
14820        self.try_insert_snippet_at_selections(action, window, cx)
14821            .log_err();
14822    }
14823
14824    fn try_insert_snippet_at_selections(
14825        &mut self,
14826        action: &InsertSnippet,
14827        window: &mut Window,
14828        cx: &mut Context<Self>,
14829    ) -> Result<()> {
14830        let insertion_ranges = self
14831            .selections
14832            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
14833            .into_iter()
14834            .map(|selection| selection.range())
14835            .collect_vec();
14836
14837        let snippet = if let Some(snippet_body) = &action.snippet {
14838            if action.language.is_none() && action.name.is_none() {
14839                Snippet::parse(snippet_body)?
14840            } else {
14841                bail!("`snippet` is mutually exclusive with `language` and `name`")
14842            }
14843        } else if let Some(name) = &action.name {
14844            let project = self.project().context("no project")?;
14845            let snippet_store = project.read(cx).snippets().read(cx);
14846            let snippet = snippet_store
14847                .snippets_for(action.language.clone(), cx)
14848                .into_iter()
14849                .find(|snippet| snippet.name == *name)
14850                .context("snippet not found")?;
14851            Snippet::parse(&snippet.body)?
14852        } else {
14853            // todo(andrew): open modal to select snippet
14854            bail!("`name` or `snippet` is required")
14855        };
14856
14857        self.insert_snippet(&insertion_ranges, snippet, window, cx)
14858    }
14859
14860    fn select_match_ranges(
14861        &mut self,
14862        range: Range<MultiBufferOffset>,
14863        reversed: bool,
14864        replace_newest: bool,
14865        auto_scroll: Option<Autoscroll>,
14866        window: &mut Window,
14867        cx: &mut Context<Editor>,
14868    ) {
14869        self.unfold_ranges(
14870            std::slice::from_ref(&range),
14871            false,
14872            auto_scroll.is_some(),
14873            cx,
14874        );
14875        let effects = if let Some(scroll) = auto_scroll {
14876            SelectionEffects::scroll(scroll)
14877        } else {
14878            SelectionEffects::no_scroll()
14879        };
14880        self.change_selections(effects, window, cx, |s| {
14881            if replace_newest {
14882                s.delete(s.newest_anchor().id);
14883            }
14884            if reversed {
14885                s.insert_range(range.end..range.start);
14886            } else {
14887                s.insert_range(range);
14888            }
14889        });
14890    }
14891
14892    pub fn select_next_match_internal(
14893        &mut self,
14894        display_map: &DisplaySnapshot,
14895        replace_newest: bool,
14896        autoscroll: Option<Autoscroll>,
14897        window: &mut Window,
14898        cx: &mut Context<Self>,
14899    ) -> Result<()> {
14900        let buffer = display_map.buffer_snapshot();
14901        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14902        if let Some(mut select_next_state) = self.select_next_state.take() {
14903            let query = &select_next_state.query;
14904            if !select_next_state.done {
14905                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14906                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14907                let mut next_selected_range = None;
14908
14909                let bytes_after_last_selection =
14910                    buffer.bytes_in_range(last_selection.end..buffer.len());
14911                let bytes_before_first_selection =
14912                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
14913                let query_matches = query
14914                    .stream_find_iter(bytes_after_last_selection)
14915                    .map(|result| (last_selection.end, result))
14916                    .chain(
14917                        query
14918                            .stream_find_iter(bytes_before_first_selection)
14919                            .map(|result| (MultiBufferOffset(0), result)),
14920                    );
14921
14922                for (start_offset, query_match) in query_matches {
14923                    let query_match = query_match.unwrap(); // can only fail due to I/O
14924                    let offset_range =
14925                        start_offset + query_match.start()..start_offset + query_match.end();
14926
14927                    if !select_next_state.wordwise
14928                        || (!buffer.is_inside_word(offset_range.start, None)
14929                            && !buffer.is_inside_word(offset_range.end, None))
14930                    {
14931                        let idx = selections
14932                            .partition_point(|selection| selection.end <= offset_range.start);
14933                        let overlaps = selections
14934                            .get(idx)
14935                            .map_or(false, |selection| selection.start < offset_range.end);
14936
14937                        if !overlaps {
14938                            next_selected_range = Some(offset_range);
14939                            break;
14940                        }
14941                    }
14942                }
14943
14944                if let Some(next_selected_range) = next_selected_range {
14945                    self.select_match_ranges(
14946                        next_selected_range,
14947                        last_selection.reversed,
14948                        replace_newest,
14949                        autoscroll,
14950                        window,
14951                        cx,
14952                    );
14953                } else {
14954                    select_next_state.done = true;
14955                }
14956            }
14957
14958            self.select_next_state = Some(select_next_state);
14959        } else {
14960            let mut only_carets = true;
14961            let mut same_text_selected = true;
14962            let mut selected_text = None;
14963
14964            let mut selections_iter = selections.iter().peekable();
14965            while let Some(selection) = selections_iter.next() {
14966                if selection.start != selection.end {
14967                    only_carets = false;
14968                }
14969
14970                if same_text_selected {
14971                    if selected_text.is_none() {
14972                        selected_text =
14973                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14974                    }
14975
14976                    if let Some(next_selection) = selections_iter.peek() {
14977                        if next_selection.len() == selection.len() {
14978                            let next_selected_text = buffer
14979                                .text_for_range(next_selection.range())
14980                                .collect::<String>();
14981                            if Some(next_selected_text) != selected_text {
14982                                same_text_selected = false;
14983                                selected_text = None;
14984                            }
14985                        } else {
14986                            same_text_selected = false;
14987                            selected_text = None;
14988                        }
14989                    }
14990                }
14991            }
14992
14993            if only_carets {
14994                for selection in &mut selections {
14995                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14996                    selection.start = word_range.start;
14997                    selection.end = word_range.end;
14998                    selection.goal = SelectionGoal::None;
14999                    selection.reversed = false;
15000                    self.select_match_ranges(
15001                        selection.start..selection.end,
15002                        selection.reversed,
15003                        replace_newest,
15004                        autoscroll,
15005                        window,
15006                        cx,
15007                    );
15008                }
15009
15010                if selections.len() == 1 {
15011                    let selection = selections
15012                        .last()
15013                        .expect("ensured that there's only one selection");
15014                    let query = buffer
15015                        .text_for_range(selection.start..selection.end)
15016                        .collect::<String>();
15017                    let is_empty = query.is_empty();
15018                    let select_state = SelectNextState {
15019                        query: self.build_query(&[query], cx)?,
15020                        wordwise: true,
15021                        done: is_empty,
15022                    };
15023                    self.select_next_state = Some(select_state);
15024                } else {
15025                    self.select_next_state = None;
15026                }
15027            } else if let Some(selected_text) = selected_text {
15028                self.select_next_state = Some(SelectNextState {
15029                    query: self.build_query(&[selected_text], cx)?,
15030                    wordwise: false,
15031                    done: false,
15032                });
15033                self.select_next_match_internal(
15034                    display_map,
15035                    replace_newest,
15036                    autoscroll,
15037                    window,
15038                    cx,
15039                )?;
15040            }
15041        }
15042        Ok(())
15043    }
15044
15045    pub fn select_all_matches(
15046        &mut self,
15047        _action: &SelectAllMatches,
15048        window: &mut Window,
15049        cx: &mut Context<Self>,
15050    ) -> Result<()> {
15051        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15052
15053        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15054
15055        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15056        let Some(select_next_state) = self.select_next_state.as_mut() else {
15057            return Ok(());
15058        };
15059        if select_next_state.done {
15060            return Ok(());
15061        }
15062
15063        let mut new_selections = Vec::new();
15064
15065        let reversed = self
15066            .selections
15067            .oldest::<MultiBufferOffset>(&display_map)
15068            .reversed;
15069        let buffer = display_map.buffer_snapshot();
15070        let query_matches = select_next_state
15071            .query
15072            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15073
15074        for query_match in query_matches.into_iter() {
15075            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15076            let offset_range = if reversed {
15077                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15078            } else {
15079                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15080            };
15081
15082            if !select_next_state.wordwise
15083                || (!buffer.is_inside_word(offset_range.start, None)
15084                    && !buffer.is_inside_word(offset_range.end, None))
15085            {
15086                new_selections.push(offset_range.start..offset_range.end);
15087            }
15088        }
15089
15090        select_next_state.done = true;
15091
15092        if new_selections.is_empty() {
15093            log::error!("bug: new_selections is empty in select_all_matches");
15094            return Ok(());
15095        }
15096
15097        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15098        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15099            selections.select_ranges(new_selections)
15100        });
15101
15102        Ok(())
15103    }
15104
15105    pub fn select_next(
15106        &mut self,
15107        action: &SelectNext,
15108        window: &mut Window,
15109        cx: &mut Context<Self>,
15110    ) -> Result<()> {
15111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15112        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15113        self.select_next_match_internal(
15114            &display_map,
15115            action.replace_newest,
15116            Some(Autoscroll::newest()),
15117            window,
15118            cx,
15119        )?;
15120        Ok(())
15121    }
15122
15123    pub fn select_previous(
15124        &mut self,
15125        action: &SelectPrevious,
15126        window: &mut Window,
15127        cx: &mut Context<Self>,
15128    ) -> Result<()> {
15129        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15130        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15131        let buffer = display_map.buffer_snapshot();
15132        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15133        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15134            let query = &select_prev_state.query;
15135            if !select_prev_state.done {
15136                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15137                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15138                let mut next_selected_range = None;
15139                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15140                let bytes_before_last_selection =
15141                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15142                let bytes_after_first_selection =
15143                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15144                let query_matches = query
15145                    .stream_find_iter(bytes_before_last_selection)
15146                    .map(|result| (last_selection.start, result))
15147                    .chain(
15148                        query
15149                            .stream_find_iter(bytes_after_first_selection)
15150                            .map(|result| (buffer.len(), result)),
15151                    );
15152                for (end_offset, query_match) in query_matches {
15153                    let query_match = query_match.unwrap(); // can only fail due to I/O
15154                    let offset_range =
15155                        end_offset - query_match.end()..end_offset - query_match.start();
15156
15157                    if !select_prev_state.wordwise
15158                        || (!buffer.is_inside_word(offset_range.start, None)
15159                            && !buffer.is_inside_word(offset_range.end, None))
15160                    {
15161                        next_selected_range = Some(offset_range);
15162                        break;
15163                    }
15164                }
15165
15166                if let Some(next_selected_range) = next_selected_range {
15167                    self.select_match_ranges(
15168                        next_selected_range,
15169                        last_selection.reversed,
15170                        action.replace_newest,
15171                        Some(Autoscroll::newest()),
15172                        window,
15173                        cx,
15174                    );
15175                } else {
15176                    select_prev_state.done = true;
15177                }
15178            }
15179
15180            self.select_prev_state = Some(select_prev_state);
15181        } else {
15182            let mut only_carets = true;
15183            let mut same_text_selected = true;
15184            let mut selected_text = None;
15185
15186            let mut selections_iter = selections.iter().peekable();
15187            while let Some(selection) = selections_iter.next() {
15188                if selection.start != selection.end {
15189                    only_carets = false;
15190                }
15191
15192                if same_text_selected {
15193                    if selected_text.is_none() {
15194                        selected_text =
15195                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15196                    }
15197
15198                    if let Some(next_selection) = selections_iter.peek() {
15199                        if next_selection.len() == selection.len() {
15200                            let next_selected_text = buffer
15201                                .text_for_range(next_selection.range())
15202                                .collect::<String>();
15203                            if Some(next_selected_text) != selected_text {
15204                                same_text_selected = false;
15205                                selected_text = None;
15206                            }
15207                        } else {
15208                            same_text_selected = false;
15209                            selected_text = None;
15210                        }
15211                    }
15212                }
15213            }
15214
15215            if only_carets {
15216                for selection in &mut selections {
15217                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15218                    selection.start = word_range.start;
15219                    selection.end = word_range.end;
15220                    selection.goal = SelectionGoal::None;
15221                    selection.reversed = false;
15222                    self.select_match_ranges(
15223                        selection.start..selection.end,
15224                        selection.reversed,
15225                        action.replace_newest,
15226                        Some(Autoscroll::newest()),
15227                        window,
15228                        cx,
15229                    );
15230                }
15231                if selections.len() == 1 {
15232                    let selection = selections
15233                        .last()
15234                        .expect("ensured that there's only one selection");
15235                    let query = buffer
15236                        .text_for_range(selection.start..selection.end)
15237                        .collect::<String>();
15238                    let is_empty = query.is_empty();
15239                    let select_state = SelectNextState {
15240                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15241                        wordwise: true,
15242                        done: is_empty,
15243                    };
15244                    self.select_prev_state = Some(select_state);
15245                } else {
15246                    self.select_prev_state = None;
15247                }
15248            } else if let Some(selected_text) = selected_text {
15249                self.select_prev_state = Some(SelectNextState {
15250                    query: self
15251                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15252                    wordwise: false,
15253                    done: false,
15254                });
15255                self.select_previous(action, window, cx)?;
15256            }
15257        }
15258        Ok(())
15259    }
15260
15261    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15262    /// setting the case sensitivity based on the global
15263    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15264    /// editor's settings.
15265    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15266    where
15267        I: IntoIterator<Item = P>,
15268        P: AsRef<[u8]>,
15269    {
15270        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15271            || EditorSettings::get_global(cx).search.case_sensitive,
15272            |value| value,
15273        );
15274
15275        let mut builder = AhoCorasickBuilder::new();
15276        builder.ascii_case_insensitive(!case_sensitive);
15277        builder.build(patterns)
15278    }
15279
15280    pub fn find_next_match(
15281        &mut self,
15282        _: &FindNextMatch,
15283        window: &mut Window,
15284        cx: &mut Context<Self>,
15285    ) -> Result<()> {
15286        let selections = self.selections.disjoint_anchors_arc();
15287        match selections.first() {
15288            Some(first) if selections.len() >= 2 => {
15289                self.change_selections(Default::default(), window, cx, |s| {
15290                    s.select_ranges([first.range()]);
15291                });
15292            }
15293            _ => self.select_next(
15294                &SelectNext {
15295                    replace_newest: true,
15296                },
15297                window,
15298                cx,
15299            )?,
15300        }
15301        Ok(())
15302    }
15303
15304    pub fn find_previous_match(
15305        &mut self,
15306        _: &FindPreviousMatch,
15307        window: &mut Window,
15308        cx: &mut Context<Self>,
15309    ) -> Result<()> {
15310        let selections = self.selections.disjoint_anchors_arc();
15311        match selections.last() {
15312            Some(last) if selections.len() >= 2 => {
15313                self.change_selections(Default::default(), window, cx, |s| {
15314                    s.select_ranges([last.range()]);
15315                });
15316            }
15317            _ => self.select_previous(
15318                &SelectPrevious {
15319                    replace_newest: true,
15320                },
15321                window,
15322                cx,
15323            )?,
15324        }
15325        Ok(())
15326    }
15327
15328    pub fn toggle_comments(
15329        &mut self,
15330        action: &ToggleComments,
15331        window: &mut Window,
15332        cx: &mut Context<Self>,
15333    ) {
15334        if self.read_only(cx) {
15335            return;
15336        }
15337        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15338        let text_layout_details = &self.text_layout_details(window);
15339        self.transact(window, cx, |this, window, cx| {
15340            let mut selections = this
15341                .selections
15342                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15343            let mut edits = Vec::new();
15344            let mut selection_edit_ranges = Vec::new();
15345            let mut last_toggled_row = None;
15346            let snapshot = this.buffer.read(cx).read(cx);
15347            let empty_str: Arc<str> = Arc::default();
15348            let mut suffixes_inserted = Vec::new();
15349            let ignore_indent = action.ignore_indent;
15350
15351            fn comment_prefix_range(
15352                snapshot: &MultiBufferSnapshot,
15353                row: MultiBufferRow,
15354                comment_prefix: &str,
15355                comment_prefix_whitespace: &str,
15356                ignore_indent: bool,
15357            ) -> Range<Point> {
15358                let indent_size = if ignore_indent {
15359                    0
15360                } else {
15361                    snapshot.indent_size_for_line(row).len
15362                };
15363
15364                let start = Point::new(row.0, indent_size);
15365
15366                let mut line_bytes = snapshot
15367                    .bytes_in_range(start..snapshot.max_point())
15368                    .flatten()
15369                    .copied();
15370
15371                // If this line currently begins with the line comment prefix, then record
15372                // the range containing the prefix.
15373                if line_bytes
15374                    .by_ref()
15375                    .take(comment_prefix.len())
15376                    .eq(comment_prefix.bytes())
15377                {
15378                    // Include any whitespace that matches the comment prefix.
15379                    let matching_whitespace_len = line_bytes
15380                        .zip(comment_prefix_whitespace.bytes())
15381                        .take_while(|(a, b)| a == b)
15382                        .count() as u32;
15383                    let end = Point::new(
15384                        start.row,
15385                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15386                    );
15387                    start..end
15388                } else {
15389                    start..start
15390                }
15391            }
15392
15393            fn comment_suffix_range(
15394                snapshot: &MultiBufferSnapshot,
15395                row: MultiBufferRow,
15396                comment_suffix: &str,
15397                comment_suffix_has_leading_space: bool,
15398            ) -> Range<Point> {
15399                let end = Point::new(row.0, snapshot.line_len(row));
15400                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15401
15402                let mut line_end_bytes = snapshot
15403                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15404                    .flatten()
15405                    .copied();
15406
15407                let leading_space_len = if suffix_start_column > 0
15408                    && line_end_bytes.next() == Some(b' ')
15409                    && comment_suffix_has_leading_space
15410                {
15411                    1
15412                } else {
15413                    0
15414                };
15415
15416                // If this line currently begins with the line comment prefix, then record
15417                // the range containing the prefix.
15418                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15419                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15420                    start..end
15421                } else {
15422                    end..end
15423                }
15424            }
15425
15426            // TODO: Handle selections that cross excerpts
15427            for selection in &mut selections {
15428                let start_column = snapshot
15429                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15430                    .len;
15431                let language = if let Some(language) =
15432                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15433                {
15434                    language
15435                } else {
15436                    continue;
15437                };
15438
15439                selection_edit_ranges.clear();
15440
15441                // If multiple selections contain a given row, avoid processing that
15442                // row more than once.
15443                let mut start_row = MultiBufferRow(selection.start.row);
15444                if last_toggled_row == Some(start_row) {
15445                    start_row = start_row.next_row();
15446                }
15447                let end_row =
15448                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15449                        MultiBufferRow(selection.end.row - 1)
15450                    } else {
15451                        MultiBufferRow(selection.end.row)
15452                    };
15453                last_toggled_row = Some(end_row);
15454
15455                if start_row > end_row {
15456                    continue;
15457                }
15458
15459                // If the language has line comments, toggle those.
15460                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15461
15462                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15463                if ignore_indent {
15464                    full_comment_prefixes = full_comment_prefixes
15465                        .into_iter()
15466                        .map(|s| Arc::from(s.trim_end()))
15467                        .collect();
15468                }
15469
15470                if !full_comment_prefixes.is_empty() {
15471                    let first_prefix = full_comment_prefixes
15472                        .first()
15473                        .expect("prefixes is non-empty");
15474                    let prefix_trimmed_lengths = full_comment_prefixes
15475                        .iter()
15476                        .map(|p| p.trim_end_matches(' ').len())
15477                        .collect::<SmallVec<[usize; 4]>>();
15478
15479                    let mut all_selection_lines_are_comments = true;
15480
15481                    for row in start_row.0..=end_row.0 {
15482                        let row = MultiBufferRow(row);
15483                        if start_row < end_row && snapshot.is_line_blank(row) {
15484                            continue;
15485                        }
15486
15487                        let prefix_range = full_comment_prefixes
15488                            .iter()
15489                            .zip(prefix_trimmed_lengths.iter().copied())
15490                            .map(|(prefix, trimmed_prefix_len)| {
15491                                comment_prefix_range(
15492                                    snapshot.deref(),
15493                                    row,
15494                                    &prefix[..trimmed_prefix_len],
15495                                    &prefix[trimmed_prefix_len..],
15496                                    ignore_indent,
15497                                )
15498                            })
15499                            .max_by_key(|range| range.end.column - range.start.column)
15500                            .expect("prefixes is non-empty");
15501
15502                        if prefix_range.is_empty() {
15503                            all_selection_lines_are_comments = false;
15504                        }
15505
15506                        selection_edit_ranges.push(prefix_range);
15507                    }
15508
15509                    if all_selection_lines_are_comments {
15510                        edits.extend(
15511                            selection_edit_ranges
15512                                .iter()
15513                                .cloned()
15514                                .map(|range| (range, empty_str.clone())),
15515                        );
15516                    } else {
15517                        let min_column = selection_edit_ranges
15518                            .iter()
15519                            .map(|range| range.start.column)
15520                            .min()
15521                            .unwrap_or(0);
15522                        edits.extend(selection_edit_ranges.iter().map(|range| {
15523                            let position = Point::new(range.start.row, min_column);
15524                            (position..position, first_prefix.clone())
15525                        }));
15526                    }
15527                } else if let Some(BlockCommentConfig {
15528                    start: full_comment_prefix,
15529                    end: comment_suffix,
15530                    ..
15531                }) = language.block_comment()
15532                {
15533                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15534                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15535                    let prefix_range = comment_prefix_range(
15536                        snapshot.deref(),
15537                        start_row,
15538                        comment_prefix,
15539                        comment_prefix_whitespace,
15540                        ignore_indent,
15541                    );
15542                    let suffix_range = comment_suffix_range(
15543                        snapshot.deref(),
15544                        end_row,
15545                        comment_suffix.trim_start_matches(' '),
15546                        comment_suffix.starts_with(' '),
15547                    );
15548
15549                    if prefix_range.is_empty() || suffix_range.is_empty() {
15550                        edits.push((
15551                            prefix_range.start..prefix_range.start,
15552                            full_comment_prefix.clone(),
15553                        ));
15554                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15555                        suffixes_inserted.push((end_row, comment_suffix.len()));
15556                    } else {
15557                        edits.push((prefix_range, empty_str.clone()));
15558                        edits.push((suffix_range, empty_str.clone()));
15559                    }
15560                } else {
15561                    continue;
15562                }
15563            }
15564
15565            drop(snapshot);
15566            this.buffer.update(cx, |buffer, cx| {
15567                buffer.edit(edits, None, cx);
15568            });
15569
15570            // Adjust selections so that they end before any comment suffixes that
15571            // were inserted.
15572            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15573            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15574            let snapshot = this.buffer.read(cx).read(cx);
15575            for selection in &mut selections {
15576                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15577                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15578                        Ordering::Less => {
15579                            suffixes_inserted.next();
15580                            continue;
15581                        }
15582                        Ordering::Greater => break,
15583                        Ordering::Equal => {
15584                            if selection.end.column == snapshot.line_len(row) {
15585                                if selection.is_empty() {
15586                                    selection.start.column -= suffix_len as u32;
15587                                }
15588                                selection.end.column -= suffix_len as u32;
15589                            }
15590                            break;
15591                        }
15592                    }
15593                }
15594            }
15595
15596            drop(snapshot);
15597            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15598
15599            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15600            let selections_on_single_row = selections.windows(2).all(|selections| {
15601                selections[0].start.row == selections[1].start.row
15602                    && selections[0].end.row == selections[1].end.row
15603                    && selections[0].start.row == selections[0].end.row
15604            });
15605            let selections_selecting = selections
15606                .iter()
15607                .any(|selection| selection.start != selection.end);
15608            let advance_downwards = action.advance_downwards
15609                && selections_on_single_row
15610                && !selections_selecting
15611                && !matches!(this.mode, EditorMode::SingleLine);
15612
15613            if advance_downwards {
15614                let snapshot = this.buffer.read(cx).snapshot(cx);
15615
15616                this.change_selections(Default::default(), window, cx, |s| {
15617                    s.move_cursors_with(|display_snapshot, display_point, _| {
15618                        let mut point = display_point.to_point(display_snapshot);
15619                        point.row += 1;
15620                        point = snapshot.clip_point(point, Bias::Left);
15621                        let display_point = point.to_display_point(display_snapshot);
15622                        let goal = SelectionGoal::HorizontalPosition(
15623                            display_snapshot
15624                                .x_for_display_point(display_point, text_layout_details)
15625                                .into(),
15626                        );
15627                        (display_point, goal)
15628                    })
15629                });
15630            }
15631        });
15632    }
15633
15634    pub fn select_enclosing_symbol(
15635        &mut self,
15636        _: &SelectEnclosingSymbol,
15637        window: &mut Window,
15638        cx: &mut Context<Self>,
15639    ) {
15640        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15641
15642        let buffer = self.buffer.read(cx).snapshot(cx);
15643        let old_selections = self
15644            .selections
15645            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15646            .into_boxed_slice();
15647
15648        fn update_selection(
15649            selection: &Selection<MultiBufferOffset>,
15650            buffer_snap: &MultiBufferSnapshot,
15651        ) -> Option<Selection<MultiBufferOffset>> {
15652            let cursor = selection.head();
15653            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15654            for symbol in symbols.iter().rev() {
15655                let start = symbol.range.start.to_offset(buffer_snap);
15656                let end = symbol.range.end.to_offset(buffer_snap);
15657                let new_range = start..end;
15658                if start < selection.start || end > selection.end {
15659                    return Some(Selection {
15660                        id: selection.id,
15661                        start: new_range.start,
15662                        end: new_range.end,
15663                        goal: SelectionGoal::None,
15664                        reversed: selection.reversed,
15665                    });
15666                }
15667            }
15668            None
15669        }
15670
15671        let mut selected_larger_symbol = false;
15672        let new_selections = old_selections
15673            .iter()
15674            .map(|selection| match update_selection(selection, &buffer) {
15675                Some(new_selection) => {
15676                    if new_selection.range() != selection.range() {
15677                        selected_larger_symbol = true;
15678                    }
15679                    new_selection
15680                }
15681                None => selection.clone(),
15682            })
15683            .collect::<Vec<_>>();
15684
15685        if selected_larger_symbol {
15686            self.change_selections(Default::default(), window, cx, |s| {
15687                s.select(new_selections);
15688            });
15689        }
15690    }
15691
15692    pub fn select_larger_syntax_node(
15693        &mut self,
15694        _: &SelectLargerSyntaxNode,
15695        window: &mut Window,
15696        cx: &mut Context<Self>,
15697    ) {
15698        let Some(visible_row_count) = self.visible_row_count() else {
15699            return;
15700        };
15701        let old_selections: Box<[_]> = self
15702            .selections
15703            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15704            .into();
15705        if old_selections.is_empty() {
15706            return;
15707        }
15708
15709        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15710
15711        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15712        let buffer = self.buffer.read(cx).snapshot(cx);
15713
15714        let mut selected_larger_node = false;
15715        let mut new_selections = old_selections
15716            .iter()
15717            .map(|selection| {
15718                let old_range = selection.start..selection.end;
15719
15720                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15721                    // manually select word at selection
15722                    if ["string_content", "inline"].contains(&node.kind()) {
15723                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15724                        // ignore if word is already selected
15725                        if !word_range.is_empty() && old_range != word_range {
15726                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15727                            // only select word if start and end point belongs to same word
15728                            if word_range == last_word_range {
15729                                selected_larger_node = true;
15730                                return Selection {
15731                                    id: selection.id,
15732                                    start: word_range.start,
15733                                    end: word_range.end,
15734                                    goal: SelectionGoal::None,
15735                                    reversed: selection.reversed,
15736                                };
15737                            }
15738                        }
15739                    }
15740                }
15741
15742                let mut new_range = old_range.clone();
15743                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15744                    new_range = range;
15745                    if !node.is_named() {
15746                        continue;
15747                    }
15748                    if !display_map.intersects_fold(new_range.start)
15749                        && !display_map.intersects_fold(new_range.end)
15750                    {
15751                        break;
15752                    }
15753                }
15754
15755                selected_larger_node |= new_range != old_range;
15756                Selection {
15757                    id: selection.id,
15758                    start: new_range.start,
15759                    end: new_range.end,
15760                    goal: SelectionGoal::None,
15761                    reversed: selection.reversed,
15762                }
15763            })
15764            .collect::<Vec<_>>();
15765
15766        if !selected_larger_node {
15767            return; // don't put this call in the history
15768        }
15769
15770        // scroll based on transformation done to the last selection created by the user
15771        let (last_old, last_new) = old_selections
15772            .last()
15773            .zip(new_selections.last().cloned())
15774            .expect("old_selections isn't empty");
15775
15776        // revert selection
15777        let is_selection_reversed = {
15778            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15779            new_selections.last_mut().expect("checked above").reversed =
15780                should_newest_selection_be_reversed;
15781            should_newest_selection_be_reversed
15782        };
15783
15784        if selected_larger_node {
15785            self.select_syntax_node_history.disable_clearing = true;
15786            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15787                s.select(new_selections.clone());
15788            });
15789            self.select_syntax_node_history.disable_clearing = false;
15790        }
15791
15792        let start_row = last_new.start.to_display_point(&display_map).row().0;
15793        let end_row = last_new.end.to_display_point(&display_map).row().0;
15794        let selection_height = end_row - start_row + 1;
15795        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15796
15797        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15798        let scroll_behavior = if fits_on_the_screen {
15799            self.request_autoscroll(Autoscroll::fit(), cx);
15800            SelectSyntaxNodeScrollBehavior::FitSelection
15801        } else if is_selection_reversed {
15802            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15803            SelectSyntaxNodeScrollBehavior::CursorTop
15804        } else {
15805            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15806            SelectSyntaxNodeScrollBehavior::CursorBottom
15807        };
15808
15809        self.select_syntax_node_history.push((
15810            old_selections,
15811            scroll_behavior,
15812            is_selection_reversed,
15813        ));
15814    }
15815
15816    pub fn select_smaller_syntax_node(
15817        &mut self,
15818        _: &SelectSmallerSyntaxNode,
15819        window: &mut Window,
15820        cx: &mut Context<Self>,
15821    ) {
15822        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15823
15824        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15825            self.select_syntax_node_history.pop()
15826        {
15827            if let Some(selection) = selections.last_mut() {
15828                selection.reversed = is_selection_reversed;
15829            }
15830
15831            self.select_syntax_node_history.disable_clearing = true;
15832            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15833                s.select(selections.to_vec());
15834            });
15835            self.select_syntax_node_history.disable_clearing = false;
15836
15837            match scroll_behavior {
15838                SelectSyntaxNodeScrollBehavior::CursorTop => {
15839                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15840                }
15841                SelectSyntaxNodeScrollBehavior::FitSelection => {
15842                    self.request_autoscroll(Autoscroll::fit(), cx);
15843                }
15844                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15845                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15846                }
15847            }
15848        }
15849    }
15850
15851    pub fn unwrap_syntax_node(
15852        &mut self,
15853        _: &UnwrapSyntaxNode,
15854        window: &mut Window,
15855        cx: &mut Context<Self>,
15856    ) {
15857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15858
15859        let buffer = self.buffer.read(cx).snapshot(cx);
15860        let selections = self
15861            .selections
15862            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15863            .into_iter()
15864            // subtracting the offset requires sorting
15865            .sorted_by_key(|i| i.start);
15866
15867        let full_edits = selections
15868            .into_iter()
15869            .filter_map(|selection| {
15870                let child = if selection.is_empty()
15871                    && let Some((_, ancestor_range)) =
15872                        buffer.syntax_ancestor(selection.start..selection.end)
15873                {
15874                    ancestor_range
15875                } else {
15876                    selection.range()
15877                };
15878
15879                let mut parent = child.clone();
15880                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15881                    parent = ancestor_range;
15882                    if parent.start < child.start || parent.end > child.end {
15883                        break;
15884                    }
15885                }
15886
15887                if parent == child {
15888                    return None;
15889                }
15890                let text = buffer.text_for_range(child).collect::<String>();
15891                Some((selection.id, parent, text))
15892            })
15893            .collect::<Vec<_>>();
15894        if full_edits.is_empty() {
15895            return;
15896        }
15897
15898        self.transact(window, cx, |this, window, cx| {
15899            this.buffer.update(cx, |buffer, cx| {
15900                buffer.edit(
15901                    full_edits
15902                        .iter()
15903                        .map(|(_, p, t)| (p.clone(), t.clone()))
15904                        .collect::<Vec<_>>(),
15905                    None,
15906                    cx,
15907                );
15908            });
15909            this.change_selections(Default::default(), window, cx, |s| {
15910                let mut offset = 0;
15911                let mut selections = vec![];
15912                for (id, parent, text) in full_edits {
15913                    let start = parent.start - offset;
15914                    offset += (parent.end - parent.start) - text.len();
15915                    selections.push(Selection {
15916                        id,
15917                        start,
15918                        end: start + text.len(),
15919                        reversed: false,
15920                        goal: Default::default(),
15921                    });
15922                }
15923                s.select(selections);
15924            });
15925        });
15926    }
15927
15928    pub fn select_next_syntax_node(
15929        &mut self,
15930        _: &SelectNextSyntaxNode,
15931        window: &mut Window,
15932        cx: &mut Context<Self>,
15933    ) {
15934        let old_selections: Box<[_]> = self
15935            .selections
15936            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15937            .into();
15938        if old_selections.is_empty() {
15939            return;
15940        }
15941
15942        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15943
15944        let buffer = self.buffer.read(cx).snapshot(cx);
15945        let mut selected_sibling = false;
15946
15947        let new_selections = old_selections
15948            .iter()
15949            .map(|selection| {
15950                let old_range = selection.start..selection.end;
15951
15952                let old_range =
15953                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15954                let excerpt = buffer.excerpt_containing(old_range.clone());
15955
15956                if let Some(mut excerpt) = excerpt
15957                    && let Some(node) = excerpt
15958                        .buffer()
15959                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
15960                {
15961                    let new_range = excerpt.map_range_from_buffer(
15962                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15963                    );
15964                    selected_sibling = true;
15965                    Selection {
15966                        id: selection.id,
15967                        start: new_range.start,
15968                        end: new_range.end,
15969                        goal: SelectionGoal::None,
15970                        reversed: selection.reversed,
15971                    }
15972                } else {
15973                    selection.clone()
15974                }
15975            })
15976            .collect::<Vec<_>>();
15977
15978        if selected_sibling {
15979            self.change_selections(
15980                SelectionEffects::scroll(Autoscroll::fit()),
15981                window,
15982                cx,
15983                |s| {
15984                    s.select(new_selections);
15985                },
15986            );
15987        }
15988    }
15989
15990    pub fn select_prev_syntax_node(
15991        &mut self,
15992        _: &SelectPreviousSyntaxNode,
15993        window: &mut Window,
15994        cx: &mut Context<Self>,
15995    ) {
15996        let old_selections: Box<[_]> = self
15997            .selections
15998            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15999            .into();
16000        if old_selections.is_empty() {
16001            return;
16002        }
16003
16004        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16005
16006        let buffer = self.buffer.read(cx).snapshot(cx);
16007        let mut selected_sibling = false;
16008
16009        let new_selections = old_selections
16010            .iter()
16011            .map(|selection| {
16012                let old_range = selection.start..selection.end;
16013                let old_range =
16014                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16015                let excerpt = buffer.excerpt_containing(old_range.clone());
16016
16017                if let Some(mut excerpt) = excerpt
16018                    && let Some(node) = excerpt
16019                        .buffer()
16020                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16021                {
16022                    let new_range = excerpt.map_range_from_buffer(
16023                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16024                    );
16025                    selected_sibling = true;
16026                    Selection {
16027                        id: selection.id,
16028                        start: new_range.start,
16029                        end: new_range.end,
16030                        goal: SelectionGoal::None,
16031                        reversed: selection.reversed,
16032                    }
16033                } else {
16034                    selection.clone()
16035                }
16036            })
16037            .collect::<Vec<_>>();
16038
16039        if selected_sibling {
16040            self.change_selections(
16041                SelectionEffects::scroll(Autoscroll::fit()),
16042                window,
16043                cx,
16044                |s| {
16045                    s.select(new_selections);
16046                },
16047            );
16048        }
16049    }
16050
16051    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16052        if !EditorSettings::get_global(cx).gutter.runnables {
16053            self.clear_tasks();
16054            return Task::ready(());
16055        }
16056        let project = self.project().map(Entity::downgrade);
16057        let task_sources = self.lsp_task_sources(cx);
16058        let multi_buffer = self.buffer.downgrade();
16059        cx.spawn_in(window, async move |editor, cx| {
16060            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16061            let Some(project) = project.and_then(|p| p.upgrade()) else {
16062                return;
16063            };
16064            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16065                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16066            }) else {
16067                return;
16068            };
16069
16070            let hide_runnables = project
16071                .update(cx, |project, _| project.is_via_collab())
16072                .unwrap_or(true);
16073            if hide_runnables {
16074                return;
16075            }
16076            let new_rows =
16077                cx.background_spawn({
16078                    let snapshot = display_snapshot.clone();
16079                    async move {
16080                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16081                    }
16082                })
16083                    .await;
16084            let Ok(lsp_tasks) =
16085                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16086            else {
16087                return;
16088            };
16089            let lsp_tasks = lsp_tasks.await;
16090
16091            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16092                lsp_tasks
16093                    .into_iter()
16094                    .flat_map(|(kind, tasks)| {
16095                        tasks.into_iter().filter_map(move |(location, task)| {
16096                            Some((kind.clone(), location?, task))
16097                        })
16098                    })
16099                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16100                        let buffer = location.target.buffer;
16101                        let buffer_snapshot = buffer.read(cx).snapshot();
16102                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16103                            |(excerpt_id, snapshot, _)| {
16104                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16105                                    display_snapshot
16106                                        .buffer_snapshot()
16107                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16108                                } else {
16109                                    None
16110                                }
16111                            },
16112                        );
16113                        if let Some(offset) = offset {
16114                            let task_buffer_range =
16115                                location.target.range.to_point(&buffer_snapshot);
16116                            let context_buffer_range =
16117                                task_buffer_range.to_offset(&buffer_snapshot);
16118                            let context_range = BufferOffset(context_buffer_range.start)
16119                                ..BufferOffset(context_buffer_range.end);
16120
16121                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16122                                .or_insert_with(|| RunnableTasks {
16123                                    templates: Vec::new(),
16124                                    offset,
16125                                    column: task_buffer_range.start.column,
16126                                    extra_variables: HashMap::default(),
16127                                    context_range,
16128                                })
16129                                .templates
16130                                .push((kind, task.original_task().clone()));
16131                        }
16132
16133                        acc
16134                    })
16135            }) else {
16136                return;
16137            };
16138
16139            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16140                buffer.language_settings(cx).tasks.prefer_lsp
16141            }) else {
16142                return;
16143            };
16144
16145            let rows = Self::runnable_rows(
16146                project,
16147                display_snapshot,
16148                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16149                new_rows,
16150                cx.clone(),
16151            )
16152            .await;
16153            editor
16154                .update(cx, |editor, _| {
16155                    editor.clear_tasks();
16156                    for (key, mut value) in rows {
16157                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16158                            value.templates.extend(lsp_tasks.templates);
16159                        }
16160
16161                        editor.insert_tasks(key, value);
16162                    }
16163                    for (key, value) in lsp_tasks_by_rows {
16164                        editor.insert_tasks(key, value);
16165                    }
16166                })
16167                .ok();
16168        })
16169    }
16170    fn fetch_runnable_ranges(
16171        snapshot: &DisplaySnapshot,
16172        range: Range<Anchor>,
16173    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16174        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16175    }
16176
16177    fn runnable_rows(
16178        project: Entity<Project>,
16179        snapshot: DisplaySnapshot,
16180        prefer_lsp: bool,
16181        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16182        cx: AsyncWindowContext,
16183    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16184        cx.spawn(async move |cx| {
16185            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16186            for (run_range, mut runnable) in runnable_ranges {
16187                let Some(tasks) = cx
16188                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16189                    .ok()
16190                else {
16191                    continue;
16192                };
16193                let mut tasks = tasks.await;
16194
16195                if prefer_lsp {
16196                    tasks.retain(|(task_kind, _)| {
16197                        !matches!(task_kind, TaskSourceKind::Language { .. })
16198                    });
16199                }
16200                if tasks.is_empty() {
16201                    continue;
16202                }
16203
16204                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16205                let Some(row) = snapshot
16206                    .buffer_snapshot()
16207                    .buffer_line_for_row(MultiBufferRow(point.row))
16208                    .map(|(_, range)| range.start.row)
16209                else {
16210                    continue;
16211                };
16212
16213                let context_range =
16214                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16215                runnable_rows.push((
16216                    (runnable.buffer_id, row),
16217                    RunnableTasks {
16218                        templates: tasks,
16219                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16220                        context_range,
16221                        column: point.column,
16222                        extra_variables: runnable.extra_captures,
16223                    },
16224                ));
16225            }
16226            runnable_rows
16227        })
16228    }
16229
16230    fn templates_with_tags(
16231        project: &Entity<Project>,
16232        runnable: &mut Runnable,
16233        cx: &mut App,
16234    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16235        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16236            let (worktree_id, file) = project
16237                .buffer_for_id(runnable.buffer, cx)
16238                .and_then(|buffer| buffer.read(cx).file())
16239                .map(|file| (file.worktree_id(cx), file.clone()))
16240                .unzip();
16241
16242            (
16243                project.task_store().read(cx).task_inventory().cloned(),
16244                worktree_id,
16245                file,
16246            )
16247        });
16248
16249        let tags = mem::take(&mut runnable.tags);
16250        let language = runnable.language.clone();
16251        cx.spawn(async move |cx| {
16252            let mut templates_with_tags = Vec::new();
16253            if let Some(inventory) = inventory {
16254                for RunnableTag(tag) in tags {
16255                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16256                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16257                    }) else {
16258                        return templates_with_tags;
16259                    };
16260                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16261                        move |(_, template)| {
16262                            template.tags.iter().any(|source_tag| source_tag == &tag)
16263                        },
16264                    ));
16265                }
16266            }
16267            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16268
16269            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16270                // Strongest source wins; if we have worktree tag binding, prefer that to
16271                // global and language bindings;
16272                // if we have a global binding, prefer that to language binding.
16273                let first_mismatch = templates_with_tags
16274                    .iter()
16275                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16276                if let Some(index) = first_mismatch {
16277                    templates_with_tags.truncate(index);
16278                }
16279            }
16280
16281            templates_with_tags
16282        })
16283    }
16284
16285    pub fn move_to_enclosing_bracket(
16286        &mut self,
16287        _: &MoveToEnclosingBracket,
16288        window: &mut Window,
16289        cx: &mut Context<Self>,
16290    ) {
16291        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16292        self.change_selections(Default::default(), window, cx, |s| {
16293            s.move_offsets_with(|snapshot, selection| {
16294                let Some(enclosing_bracket_ranges) =
16295                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16296                else {
16297                    return;
16298                };
16299
16300                let mut best_length = usize::MAX;
16301                let mut best_inside = false;
16302                let mut best_in_bracket_range = false;
16303                let mut best_destination = None;
16304                for (open, close) in enclosing_bracket_ranges {
16305                    let close = close.to_inclusive();
16306                    let length = *close.end() - open.start;
16307                    let inside = selection.start >= open.end && selection.end <= *close.start();
16308                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16309                        || close.contains(&selection.head());
16310
16311                    // If best is next to a bracket and current isn't, skip
16312                    if !in_bracket_range && best_in_bracket_range {
16313                        continue;
16314                    }
16315
16316                    // Prefer smaller lengths unless best is inside and current isn't
16317                    if length > best_length && (best_inside || !inside) {
16318                        continue;
16319                    }
16320
16321                    best_length = length;
16322                    best_inside = inside;
16323                    best_in_bracket_range = in_bracket_range;
16324                    best_destination = Some(
16325                        if close.contains(&selection.start) && close.contains(&selection.end) {
16326                            if inside { open.end } else { open.start }
16327                        } else if inside {
16328                            *close.start()
16329                        } else {
16330                            *close.end()
16331                        },
16332                    );
16333                }
16334
16335                if let Some(destination) = best_destination {
16336                    selection.collapse_to(destination, SelectionGoal::None);
16337                }
16338            })
16339        });
16340    }
16341
16342    pub fn undo_selection(
16343        &mut self,
16344        _: &UndoSelection,
16345        window: &mut Window,
16346        cx: &mut Context<Self>,
16347    ) {
16348        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16349        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16350            self.selection_history.mode = SelectionHistoryMode::Undoing;
16351            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16352                this.end_selection(window, cx);
16353                this.change_selections(
16354                    SelectionEffects::scroll(Autoscroll::newest()),
16355                    window,
16356                    cx,
16357                    |s| s.select_anchors(entry.selections.to_vec()),
16358                );
16359            });
16360            self.selection_history.mode = SelectionHistoryMode::Normal;
16361
16362            self.select_next_state = entry.select_next_state;
16363            self.select_prev_state = entry.select_prev_state;
16364            self.add_selections_state = entry.add_selections_state;
16365        }
16366    }
16367
16368    pub fn redo_selection(
16369        &mut self,
16370        _: &RedoSelection,
16371        window: &mut Window,
16372        cx: &mut Context<Self>,
16373    ) {
16374        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16375        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16376            self.selection_history.mode = SelectionHistoryMode::Redoing;
16377            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16378                this.end_selection(window, cx);
16379                this.change_selections(
16380                    SelectionEffects::scroll(Autoscroll::newest()),
16381                    window,
16382                    cx,
16383                    |s| s.select_anchors(entry.selections.to_vec()),
16384                );
16385            });
16386            self.selection_history.mode = SelectionHistoryMode::Normal;
16387
16388            self.select_next_state = entry.select_next_state;
16389            self.select_prev_state = entry.select_prev_state;
16390            self.add_selections_state = entry.add_selections_state;
16391        }
16392    }
16393
16394    pub fn expand_excerpts(
16395        &mut self,
16396        action: &ExpandExcerpts,
16397        _: &mut Window,
16398        cx: &mut Context<Self>,
16399    ) {
16400        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16401    }
16402
16403    pub fn expand_excerpts_down(
16404        &mut self,
16405        action: &ExpandExcerptsDown,
16406        _: &mut Window,
16407        cx: &mut Context<Self>,
16408    ) {
16409        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16410    }
16411
16412    pub fn expand_excerpts_up(
16413        &mut self,
16414        action: &ExpandExcerptsUp,
16415        _: &mut Window,
16416        cx: &mut Context<Self>,
16417    ) {
16418        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16419    }
16420
16421    pub fn expand_excerpts_for_direction(
16422        &mut self,
16423        lines: u32,
16424        direction: ExpandExcerptDirection,
16425
16426        cx: &mut Context<Self>,
16427    ) {
16428        let selections = self.selections.disjoint_anchors_arc();
16429
16430        let lines = if lines == 0 {
16431            EditorSettings::get_global(cx).expand_excerpt_lines
16432        } else {
16433            lines
16434        };
16435
16436        self.buffer.update(cx, |buffer, cx| {
16437            let snapshot = buffer.snapshot(cx);
16438            let mut excerpt_ids = selections
16439                .iter()
16440                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16441                .collect::<Vec<_>>();
16442            excerpt_ids.sort();
16443            excerpt_ids.dedup();
16444            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16445        })
16446    }
16447
16448    pub fn expand_excerpt(
16449        &mut self,
16450        excerpt: ExcerptId,
16451        direction: ExpandExcerptDirection,
16452        window: &mut Window,
16453        cx: &mut Context<Self>,
16454    ) {
16455        let current_scroll_position = self.scroll_position(cx);
16456        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16457        let mut scroll = None;
16458
16459        if direction == ExpandExcerptDirection::Down {
16460            let multi_buffer = self.buffer.read(cx);
16461            let snapshot = multi_buffer.snapshot(cx);
16462            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16463                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16464                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16465            {
16466                let buffer_snapshot = buffer.read(cx).snapshot();
16467                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16468                let last_row = buffer_snapshot.max_point().row;
16469                let lines_below = last_row.saturating_sub(excerpt_end_row);
16470                if lines_below >= lines_to_expand {
16471                    scroll = Some(
16472                        current_scroll_position
16473                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16474                    );
16475                }
16476            }
16477        }
16478        if direction == ExpandExcerptDirection::Up
16479            && self
16480                .buffer
16481                .read(cx)
16482                .snapshot(cx)
16483                .excerpt_before(excerpt)
16484                .is_none()
16485        {
16486            scroll = Some(current_scroll_position);
16487        }
16488
16489        self.buffer.update(cx, |buffer, cx| {
16490            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16491        });
16492
16493        if let Some(new_scroll_position) = scroll {
16494            self.set_scroll_position(new_scroll_position, window, cx);
16495        }
16496    }
16497
16498    pub fn go_to_singleton_buffer_point(
16499        &mut self,
16500        point: Point,
16501        window: &mut Window,
16502        cx: &mut Context<Self>,
16503    ) {
16504        self.go_to_singleton_buffer_range(point..point, window, cx);
16505    }
16506
16507    pub fn go_to_singleton_buffer_range(
16508        &mut self,
16509        range: Range<Point>,
16510        window: &mut Window,
16511        cx: &mut Context<Self>,
16512    ) {
16513        let multibuffer = self.buffer().read(cx);
16514        let Some(buffer) = multibuffer.as_singleton() else {
16515            return;
16516        };
16517        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16518            return;
16519        };
16520        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16521            return;
16522        };
16523        self.change_selections(
16524            SelectionEffects::default().nav_history(true),
16525            window,
16526            cx,
16527            |s| s.select_anchor_ranges([start..end]),
16528        );
16529    }
16530
16531    pub fn go_to_diagnostic(
16532        &mut self,
16533        action: &GoToDiagnostic,
16534        window: &mut Window,
16535        cx: &mut Context<Self>,
16536    ) {
16537        if !self.diagnostics_enabled() {
16538            return;
16539        }
16540        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16541        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16542    }
16543
16544    pub fn go_to_prev_diagnostic(
16545        &mut self,
16546        action: &GoToPreviousDiagnostic,
16547        window: &mut Window,
16548        cx: &mut Context<Self>,
16549    ) {
16550        if !self.diagnostics_enabled() {
16551            return;
16552        }
16553        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16554        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16555    }
16556
16557    pub fn go_to_diagnostic_impl(
16558        &mut self,
16559        direction: Direction,
16560        severity: GoToDiagnosticSeverityFilter,
16561        window: &mut Window,
16562        cx: &mut Context<Self>,
16563    ) {
16564        let buffer = self.buffer.read(cx).snapshot(cx);
16565        let selection = self
16566            .selections
16567            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16568
16569        let mut active_group_id = None;
16570        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16571            && active_group.active_range.start.to_offset(&buffer) == selection.start
16572        {
16573            active_group_id = Some(active_group.group_id);
16574        }
16575
16576        fn filtered<'a>(
16577            severity: GoToDiagnosticSeverityFilter,
16578            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16579        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16580            diagnostics
16581                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16582                .filter(|entry| entry.range.start != entry.range.end)
16583                .filter(|entry| !entry.diagnostic.is_unnecessary)
16584        }
16585
16586        let before = filtered(
16587            severity,
16588            buffer
16589                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16590                .filter(|entry| entry.range.start <= selection.start),
16591        );
16592        let after = filtered(
16593            severity,
16594            buffer
16595                .diagnostics_in_range(selection.start..buffer.len())
16596                .filter(|entry| entry.range.start >= selection.start),
16597        );
16598
16599        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16600        if direction == Direction::Prev {
16601            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16602            {
16603                for diagnostic in prev_diagnostics.into_iter().rev() {
16604                    if diagnostic.range.start != selection.start
16605                        || active_group_id
16606                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16607                    {
16608                        found = Some(diagnostic);
16609                        break 'outer;
16610                    }
16611                }
16612            }
16613        } else {
16614            for diagnostic in after.chain(before) {
16615                if diagnostic.range.start != selection.start
16616                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16617                {
16618                    found = Some(diagnostic);
16619                    break;
16620                }
16621            }
16622        }
16623        let Some(next_diagnostic) = found else {
16624            return;
16625        };
16626
16627        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16628        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16629            return;
16630        };
16631        let snapshot = self.snapshot(window, cx);
16632        if snapshot.intersects_fold(next_diagnostic.range.start) {
16633            self.unfold_ranges(
16634                std::slice::from_ref(&next_diagnostic.range),
16635                true,
16636                false,
16637                cx,
16638            );
16639        }
16640        self.change_selections(Default::default(), window, cx, |s| {
16641            s.select_ranges(vec![
16642                next_diagnostic.range.start..next_diagnostic.range.start,
16643            ])
16644        });
16645        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16646        self.refresh_edit_prediction(false, true, window, cx);
16647    }
16648
16649    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16650        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16651        let snapshot = self.snapshot(window, cx);
16652        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16653        self.go_to_hunk_before_or_after_position(
16654            &snapshot,
16655            selection.head(),
16656            Direction::Next,
16657            window,
16658            cx,
16659        );
16660    }
16661
16662    pub fn go_to_hunk_before_or_after_position(
16663        &mut self,
16664        snapshot: &EditorSnapshot,
16665        position: Point,
16666        direction: Direction,
16667        window: &mut Window,
16668        cx: &mut Context<Editor>,
16669    ) {
16670        let row = if direction == Direction::Next {
16671            self.hunk_after_position(snapshot, position)
16672                .map(|hunk| hunk.row_range.start)
16673        } else {
16674            self.hunk_before_position(snapshot, position)
16675        };
16676
16677        if let Some(row) = row {
16678            let destination = Point::new(row.0, 0);
16679            let autoscroll = Autoscroll::center();
16680
16681            self.unfold_ranges(&[destination..destination], false, false, cx);
16682            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16683                s.select_ranges([destination..destination]);
16684            });
16685        }
16686    }
16687
16688    fn hunk_after_position(
16689        &mut self,
16690        snapshot: &EditorSnapshot,
16691        position: Point,
16692    ) -> Option<MultiBufferDiffHunk> {
16693        snapshot
16694            .buffer_snapshot()
16695            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16696            .find(|hunk| hunk.row_range.start.0 > position.row)
16697            .or_else(|| {
16698                snapshot
16699                    .buffer_snapshot()
16700                    .diff_hunks_in_range(Point::zero()..position)
16701                    .find(|hunk| hunk.row_range.end.0 < position.row)
16702            })
16703    }
16704
16705    fn go_to_prev_hunk(
16706        &mut self,
16707        _: &GoToPreviousHunk,
16708        window: &mut Window,
16709        cx: &mut Context<Self>,
16710    ) {
16711        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16712        let snapshot = self.snapshot(window, cx);
16713        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16714        self.go_to_hunk_before_or_after_position(
16715            &snapshot,
16716            selection.head(),
16717            Direction::Prev,
16718            window,
16719            cx,
16720        );
16721    }
16722
16723    fn hunk_before_position(
16724        &mut self,
16725        snapshot: &EditorSnapshot,
16726        position: Point,
16727    ) -> Option<MultiBufferRow> {
16728        snapshot
16729            .buffer_snapshot()
16730            .diff_hunk_before(position)
16731            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16732    }
16733
16734    fn go_to_next_change(
16735        &mut self,
16736        _: &GoToNextChange,
16737        window: &mut Window,
16738        cx: &mut Context<Self>,
16739    ) {
16740        if let Some(selections) = self
16741            .change_list
16742            .next_change(1, Direction::Next)
16743            .map(|s| s.to_vec())
16744        {
16745            self.change_selections(Default::default(), window, cx, |s| {
16746                let map = s.display_snapshot();
16747                s.select_display_ranges(selections.iter().map(|a| {
16748                    let point = a.to_display_point(&map);
16749                    point..point
16750                }))
16751            })
16752        }
16753    }
16754
16755    fn go_to_previous_change(
16756        &mut self,
16757        _: &GoToPreviousChange,
16758        window: &mut Window,
16759        cx: &mut Context<Self>,
16760    ) {
16761        if let Some(selections) = self
16762            .change_list
16763            .next_change(1, Direction::Prev)
16764            .map(|s| s.to_vec())
16765        {
16766            self.change_selections(Default::default(), window, cx, |s| {
16767                let map = s.display_snapshot();
16768                s.select_display_ranges(selections.iter().map(|a| {
16769                    let point = a.to_display_point(&map);
16770                    point..point
16771                }))
16772            })
16773        }
16774    }
16775
16776    pub fn go_to_next_document_highlight(
16777        &mut self,
16778        _: &GoToNextDocumentHighlight,
16779        window: &mut Window,
16780        cx: &mut Context<Self>,
16781    ) {
16782        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16783    }
16784
16785    pub fn go_to_prev_document_highlight(
16786        &mut self,
16787        _: &GoToPreviousDocumentHighlight,
16788        window: &mut Window,
16789        cx: &mut Context<Self>,
16790    ) {
16791        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16792    }
16793
16794    pub fn go_to_document_highlight_before_or_after_position(
16795        &mut self,
16796        direction: Direction,
16797        window: &mut Window,
16798        cx: &mut Context<Editor>,
16799    ) {
16800        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16801        let snapshot = self.snapshot(window, cx);
16802        let buffer = &snapshot.buffer_snapshot();
16803        let position = self
16804            .selections
16805            .newest::<Point>(&snapshot.display_snapshot)
16806            .head();
16807        let anchor_position = buffer.anchor_after(position);
16808
16809        // Get all document highlights (both read and write)
16810        let mut all_highlights = Vec::new();
16811
16812        if let Some((_, read_highlights)) = self
16813            .background_highlights
16814            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16815        {
16816            all_highlights.extend(read_highlights.iter());
16817        }
16818
16819        if let Some((_, write_highlights)) = self
16820            .background_highlights
16821            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16822        {
16823            all_highlights.extend(write_highlights.iter());
16824        }
16825
16826        if all_highlights.is_empty() {
16827            return;
16828        }
16829
16830        // Sort highlights by position
16831        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16832
16833        let target_highlight = match direction {
16834            Direction::Next => {
16835                // Find the first highlight after the current position
16836                all_highlights
16837                    .iter()
16838                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16839            }
16840            Direction::Prev => {
16841                // Find the last highlight before the current position
16842                all_highlights
16843                    .iter()
16844                    .rev()
16845                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16846            }
16847        };
16848
16849        if let Some(highlight) = target_highlight {
16850            let destination = highlight.start.to_point(buffer);
16851            let autoscroll = Autoscroll::center();
16852
16853            self.unfold_ranges(&[destination..destination], false, false, cx);
16854            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16855                s.select_ranges([destination..destination]);
16856            });
16857        }
16858    }
16859
16860    fn go_to_line<T: 'static>(
16861        &mut self,
16862        position: Anchor,
16863        highlight_color: Option<Hsla>,
16864        window: &mut Window,
16865        cx: &mut Context<Self>,
16866    ) {
16867        let snapshot = self.snapshot(window, cx).display_snapshot;
16868        let position = position.to_point(&snapshot.buffer_snapshot());
16869        let start = snapshot
16870            .buffer_snapshot()
16871            .clip_point(Point::new(position.row, 0), Bias::Left);
16872        let end = start + Point::new(1, 0);
16873        let start = snapshot.buffer_snapshot().anchor_before(start);
16874        let end = snapshot.buffer_snapshot().anchor_before(end);
16875
16876        self.highlight_rows::<T>(
16877            start..end,
16878            highlight_color
16879                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16880            Default::default(),
16881            cx,
16882        );
16883
16884        if self.buffer.read(cx).is_singleton() {
16885            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16886        }
16887    }
16888
16889    pub fn go_to_definition(
16890        &mut self,
16891        _: &GoToDefinition,
16892        window: &mut Window,
16893        cx: &mut Context<Self>,
16894    ) -> Task<Result<Navigated>> {
16895        let definition =
16896            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16897        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16898        cx.spawn_in(window, async move |editor, cx| {
16899            if definition.await? == Navigated::Yes {
16900                return Ok(Navigated::Yes);
16901            }
16902            match fallback_strategy {
16903                GoToDefinitionFallback::None => Ok(Navigated::No),
16904                GoToDefinitionFallback::FindAllReferences => {
16905                    match editor.update_in(cx, |editor, window, cx| {
16906                        editor.find_all_references(&FindAllReferences::default(), window, cx)
16907                    })? {
16908                        Some(references) => references.await,
16909                        None => Ok(Navigated::No),
16910                    }
16911                }
16912            }
16913        })
16914    }
16915
16916    pub fn go_to_declaration(
16917        &mut self,
16918        _: &GoToDeclaration,
16919        window: &mut Window,
16920        cx: &mut Context<Self>,
16921    ) -> Task<Result<Navigated>> {
16922        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16923    }
16924
16925    pub fn go_to_declaration_split(
16926        &mut self,
16927        _: &GoToDeclaration,
16928        window: &mut Window,
16929        cx: &mut Context<Self>,
16930    ) -> Task<Result<Navigated>> {
16931        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16932    }
16933
16934    pub fn go_to_implementation(
16935        &mut self,
16936        _: &GoToImplementation,
16937        window: &mut Window,
16938        cx: &mut Context<Self>,
16939    ) -> Task<Result<Navigated>> {
16940        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16941    }
16942
16943    pub fn go_to_implementation_split(
16944        &mut self,
16945        _: &GoToImplementationSplit,
16946        window: &mut Window,
16947        cx: &mut Context<Self>,
16948    ) -> Task<Result<Navigated>> {
16949        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16950    }
16951
16952    pub fn go_to_type_definition(
16953        &mut self,
16954        _: &GoToTypeDefinition,
16955        window: &mut Window,
16956        cx: &mut Context<Self>,
16957    ) -> Task<Result<Navigated>> {
16958        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16959    }
16960
16961    pub fn go_to_definition_split(
16962        &mut self,
16963        _: &GoToDefinitionSplit,
16964        window: &mut Window,
16965        cx: &mut Context<Self>,
16966    ) -> Task<Result<Navigated>> {
16967        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16968    }
16969
16970    pub fn go_to_type_definition_split(
16971        &mut self,
16972        _: &GoToTypeDefinitionSplit,
16973        window: &mut Window,
16974        cx: &mut Context<Self>,
16975    ) -> Task<Result<Navigated>> {
16976        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16977    }
16978
16979    fn go_to_definition_of_kind(
16980        &mut self,
16981        kind: GotoDefinitionKind,
16982        split: bool,
16983        window: &mut Window,
16984        cx: &mut Context<Self>,
16985    ) -> Task<Result<Navigated>> {
16986        let Some(provider) = self.semantics_provider.clone() else {
16987            return Task::ready(Ok(Navigated::No));
16988        };
16989        let head = self
16990            .selections
16991            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
16992            .head();
16993        let buffer = self.buffer.read(cx);
16994        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16995            return Task::ready(Ok(Navigated::No));
16996        };
16997        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16998            return Task::ready(Ok(Navigated::No));
16999        };
17000
17001        cx.spawn_in(window, async move |editor, cx| {
17002            let Some(definitions) = definitions.await? else {
17003                return Ok(Navigated::No);
17004            };
17005            let navigated = editor
17006                .update_in(cx, |editor, window, cx| {
17007                    editor.navigate_to_hover_links(
17008                        Some(kind),
17009                        definitions
17010                            .into_iter()
17011                            .filter(|location| {
17012                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17013                            })
17014                            .map(HoverLink::Text)
17015                            .collect::<Vec<_>>(),
17016                        split,
17017                        window,
17018                        cx,
17019                    )
17020                })?
17021                .await?;
17022            anyhow::Ok(navigated)
17023        })
17024    }
17025
17026    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17027        let selection = self.selections.newest_anchor();
17028        let head = selection.head();
17029        let tail = selection.tail();
17030
17031        let Some((buffer, start_position)) =
17032            self.buffer.read(cx).text_anchor_for_position(head, cx)
17033        else {
17034            return;
17035        };
17036
17037        let end_position = if head != tail {
17038            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17039                return;
17040            };
17041            Some(pos)
17042        } else {
17043            None
17044        };
17045
17046        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17047            let url = if let Some(end_pos) = end_position {
17048                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17049            } else {
17050                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17051            };
17052
17053            if let Some(url) = url {
17054                cx.update(|window, cx| {
17055                    if parse_zed_link(&url, cx).is_some() {
17056                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17057                    } else {
17058                        cx.open_url(&url);
17059                    }
17060                })?;
17061            }
17062
17063            anyhow::Ok(())
17064        });
17065
17066        url_finder.detach();
17067    }
17068
17069    pub fn open_selected_filename(
17070        &mut self,
17071        _: &OpenSelectedFilename,
17072        window: &mut Window,
17073        cx: &mut Context<Self>,
17074    ) {
17075        let Some(workspace) = self.workspace() else {
17076            return;
17077        };
17078
17079        let position = self.selections.newest_anchor().head();
17080
17081        let Some((buffer, buffer_position)) =
17082            self.buffer.read(cx).text_anchor_for_position(position, cx)
17083        else {
17084            return;
17085        };
17086
17087        let project = self.project.clone();
17088
17089        cx.spawn_in(window, async move |_, cx| {
17090            let result = find_file(&buffer, project, buffer_position, cx).await;
17091
17092            if let Some((_, path)) = result {
17093                workspace
17094                    .update_in(cx, |workspace, window, cx| {
17095                        workspace.open_resolved_path(path, window, cx)
17096                    })?
17097                    .await?;
17098            }
17099            anyhow::Ok(())
17100        })
17101        .detach();
17102    }
17103
17104    pub(crate) fn navigate_to_hover_links(
17105        &mut self,
17106        kind: Option<GotoDefinitionKind>,
17107        definitions: Vec<HoverLink>,
17108        split: bool,
17109        window: &mut Window,
17110        cx: &mut Context<Editor>,
17111    ) -> Task<Result<Navigated>> {
17112        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17113        let mut first_url_or_file = None;
17114        let definitions: Vec<_> = definitions
17115            .into_iter()
17116            .filter_map(|def| match def {
17117                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17118                HoverLink::InlayHint(lsp_location, server_id) => {
17119                    let computation =
17120                        self.compute_target_location(lsp_location, server_id, window, cx);
17121                    Some(cx.background_spawn(computation))
17122                }
17123                HoverLink::Url(url) => {
17124                    first_url_or_file = Some(Either::Left(url));
17125                    None
17126                }
17127                HoverLink::File(path) => {
17128                    first_url_or_file = Some(Either::Right(path));
17129                    None
17130                }
17131            })
17132            .collect();
17133
17134        let workspace = self.workspace();
17135
17136        cx.spawn_in(window, async move |editor, cx| {
17137            let locations: Vec<Location> = future::join_all(definitions)
17138                .await
17139                .into_iter()
17140                .filter_map(|location| location.transpose())
17141                .collect::<Result<_>>()
17142                .context("location tasks")?;
17143            let mut locations = cx.update(|_, cx| {
17144                locations
17145                    .into_iter()
17146                    .map(|location| {
17147                        let buffer = location.buffer.read(cx);
17148                        (location.buffer, location.range.to_point(buffer))
17149                    })
17150                    .into_group_map()
17151            })?;
17152            let mut num_locations = 0;
17153            for ranges in locations.values_mut() {
17154                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17155                ranges.dedup();
17156                num_locations += ranges.len();
17157            }
17158
17159            if num_locations > 1 {
17160                let tab_kind = match kind {
17161                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17162                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17163                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17164                    Some(GotoDefinitionKind::Type) => "Types",
17165                };
17166                let title = editor
17167                    .update_in(cx, |_, _, cx| {
17168                        let target = locations
17169                            .iter()
17170                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17171                            .map(|(buffer, location)| {
17172                                buffer
17173                                    .read(cx)
17174                                    .text_for_range(location.clone())
17175                                    .collect::<String>()
17176                            })
17177                            .filter(|text| !text.contains('\n'))
17178                            .unique()
17179                            .take(3)
17180                            .join(", ");
17181                        if target.is_empty() {
17182                            tab_kind.to_owned()
17183                        } else {
17184                            format!("{tab_kind} for {target}")
17185                        }
17186                    })
17187                    .context("buffer title")?;
17188
17189                let Some(workspace) = workspace else {
17190                    return Ok(Navigated::No);
17191                };
17192
17193                let opened = workspace
17194                    .update_in(cx, |workspace, window, cx| {
17195                        let allow_preview = PreviewTabsSettings::get_global(cx)
17196                            .enable_preview_multibuffer_from_code_navigation;
17197                        Self::open_locations_in_multibuffer(
17198                            workspace,
17199                            locations,
17200                            title,
17201                            split,
17202                            allow_preview,
17203                            MultibufferSelectionMode::First,
17204                            window,
17205                            cx,
17206                        )
17207                    })
17208                    .is_ok();
17209
17210                anyhow::Ok(Navigated::from_bool(opened))
17211            } else if num_locations == 0 {
17212                // If there is one url or file, open it directly
17213                match first_url_or_file {
17214                    Some(Either::Left(url)) => {
17215                        cx.update(|_, cx| cx.open_url(&url))?;
17216                        Ok(Navigated::Yes)
17217                    }
17218                    Some(Either::Right(path)) => {
17219                        // TODO(andrew): respect preview tab settings
17220                        //               `enable_keep_preview_on_code_navigation` and
17221                        //               `enable_preview_file_from_code_navigation`
17222                        let Some(workspace) = workspace else {
17223                            return Ok(Navigated::No);
17224                        };
17225                        workspace
17226                            .update_in(cx, |workspace, window, cx| {
17227                                workspace.open_resolved_path(path, window, cx)
17228                            })?
17229                            .await?;
17230                        Ok(Navigated::Yes)
17231                    }
17232                    None => Ok(Navigated::No),
17233                }
17234            } else {
17235                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17236                let target_range = target_ranges.first().unwrap().clone();
17237
17238                editor.update_in(cx, |editor, window, cx| {
17239                    let range = target_range.to_point(target_buffer.read(cx));
17240                    let range = editor.range_for_match(&range);
17241                    let range = collapse_multiline_range(range);
17242
17243                    if !split
17244                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17245                    {
17246                        editor.go_to_singleton_buffer_range(range, window, cx);
17247                    } else {
17248                        let Some(workspace) = workspace else {
17249                            return Navigated::No;
17250                        };
17251                        let pane = workspace.read(cx).active_pane().clone();
17252                        window.defer(cx, move |window, cx| {
17253                            let target_editor: Entity<Self> =
17254                                workspace.update(cx, |workspace, cx| {
17255                                    let pane = if split {
17256                                        workspace.adjacent_pane(window, cx)
17257                                    } else {
17258                                        workspace.active_pane().clone()
17259                                    };
17260
17261                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17262                                    let keep_old_preview = preview_tabs_settings
17263                                        .enable_keep_preview_on_code_navigation;
17264                                    let allow_new_preview = preview_tabs_settings
17265                                        .enable_preview_file_from_code_navigation;
17266
17267                                    workspace.open_project_item(
17268                                        pane,
17269                                        target_buffer.clone(),
17270                                        true,
17271                                        true,
17272                                        keep_old_preview,
17273                                        allow_new_preview,
17274                                        window,
17275                                        cx,
17276                                    )
17277                                });
17278                            target_editor.update(cx, |target_editor, cx| {
17279                                // When selecting a definition in a different buffer, disable the nav history
17280                                // to avoid creating a history entry at the previous cursor location.
17281                                pane.update(cx, |pane, _| pane.disable_history());
17282                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17283                                pane.update(cx, |pane, _| pane.enable_history());
17284                            });
17285                        });
17286                    }
17287                    Navigated::Yes
17288                })
17289            }
17290        })
17291    }
17292
17293    fn compute_target_location(
17294        &self,
17295        lsp_location: lsp::Location,
17296        server_id: LanguageServerId,
17297        window: &mut Window,
17298        cx: &mut Context<Self>,
17299    ) -> Task<anyhow::Result<Option<Location>>> {
17300        let Some(project) = self.project.clone() else {
17301            return Task::ready(Ok(None));
17302        };
17303
17304        cx.spawn_in(window, async move |editor, cx| {
17305            let location_task = editor.update(cx, |_, cx| {
17306                project.update(cx, |project, cx| {
17307                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17308                })
17309            })?;
17310            let location = Some({
17311                let target_buffer_handle = location_task.await.context("open local buffer")?;
17312                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17313                    let target_start = target_buffer
17314                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17315                    let target_end = target_buffer
17316                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17317                    target_buffer.anchor_after(target_start)
17318                        ..target_buffer.anchor_before(target_end)
17319                })?;
17320                Location {
17321                    buffer: target_buffer_handle,
17322                    range,
17323                }
17324            });
17325            Ok(location)
17326        })
17327    }
17328
17329    fn go_to_next_reference(
17330        &mut self,
17331        _: &GoToNextReference,
17332        window: &mut Window,
17333        cx: &mut Context<Self>,
17334    ) {
17335        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17336        if let Some(task) = task {
17337            task.detach();
17338        };
17339    }
17340
17341    fn go_to_prev_reference(
17342        &mut self,
17343        _: &GoToPreviousReference,
17344        window: &mut Window,
17345        cx: &mut Context<Self>,
17346    ) {
17347        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17348        if let Some(task) = task {
17349            task.detach();
17350        };
17351    }
17352
17353    pub fn go_to_reference_before_or_after_position(
17354        &mut self,
17355        direction: Direction,
17356        count: usize,
17357        window: &mut Window,
17358        cx: &mut Context<Self>,
17359    ) -> Option<Task<Result<()>>> {
17360        let selection = self.selections.newest_anchor();
17361        let head = selection.head();
17362
17363        let multi_buffer = self.buffer.read(cx);
17364
17365        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17366        let workspace = self.workspace()?;
17367        let project = workspace.read(cx).project().clone();
17368        let references =
17369            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17370        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17371            let Some(locations) = references.await? else {
17372                return Ok(());
17373            };
17374
17375            if locations.is_empty() {
17376                // totally normal - the cursor may be on something which is not
17377                // a symbol (e.g. a keyword)
17378                log::info!("no references found under cursor");
17379                return Ok(());
17380            }
17381
17382            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17383
17384            let (locations, current_location_index) =
17385                multi_buffer.update(cx, |multi_buffer, cx| {
17386                    let mut locations = locations
17387                        .into_iter()
17388                        .filter_map(|loc| {
17389                            let start = multi_buffer.buffer_anchor_to_anchor(
17390                                &loc.buffer,
17391                                loc.range.start,
17392                                cx,
17393                            )?;
17394                            let end = multi_buffer.buffer_anchor_to_anchor(
17395                                &loc.buffer,
17396                                loc.range.end,
17397                                cx,
17398                            )?;
17399                            Some(start..end)
17400                        })
17401                        .collect::<Vec<_>>();
17402
17403                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17404                    // There is an O(n) implementation, but given this list will be
17405                    // small (usually <100 items), the extra O(log(n)) factor isn't
17406                    // worth the (surprisingly large amount of) extra complexity.
17407                    locations
17408                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17409
17410                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17411
17412                    let current_location_index = locations.iter().position(|loc| {
17413                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17414                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17415                    });
17416
17417                    (locations, current_location_index)
17418                })?;
17419
17420            let Some(current_location_index) = current_location_index else {
17421                // This indicates something has gone wrong, because we already
17422                // handle the "no references" case above
17423                log::error!(
17424                    "failed to find current reference under cursor. Total references: {}",
17425                    locations.len()
17426                );
17427                return Ok(());
17428            };
17429
17430            let destination_location_index = match direction {
17431                Direction::Next => (current_location_index + count) % locations.len(),
17432                Direction::Prev => {
17433                    (current_location_index + locations.len() - count % locations.len())
17434                        % locations.len()
17435                }
17436            };
17437
17438            // TODO(cameron): is this needed?
17439            // the thinking is to avoid "jumping to the current location" (avoid
17440            // polluting "jumplist" in vim terms)
17441            if current_location_index == destination_location_index {
17442                return Ok(());
17443            }
17444
17445            let Range { start, end } = locations[destination_location_index];
17446
17447            editor.update_in(cx, |editor, window, cx| {
17448                let effects = SelectionEffects::default();
17449
17450                editor.unfold_ranges(&[start..end], false, false, cx);
17451                editor.change_selections(effects, window, cx, |s| {
17452                    s.select_ranges([start..start]);
17453                });
17454            })?;
17455
17456            Ok(())
17457        }))
17458    }
17459
17460    pub fn find_all_references(
17461        &mut self,
17462        action: &FindAllReferences,
17463        window: &mut Window,
17464        cx: &mut Context<Self>,
17465    ) -> Option<Task<Result<Navigated>>> {
17466        let always_open_multibuffer = action.always_open_multibuffer;
17467        let selection = self.selections.newest_anchor();
17468        let multi_buffer = self.buffer.read(cx);
17469        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17470        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17471        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17472        let head = selection_offset.head();
17473
17474        let head_anchor = multi_buffer_snapshot.anchor_at(
17475            head,
17476            if head < selection_offset.tail() {
17477                Bias::Right
17478            } else {
17479                Bias::Left
17480            },
17481        );
17482
17483        match self
17484            .find_all_references_task_sources
17485            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17486        {
17487            Ok(_) => {
17488                log::info!(
17489                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17490                );
17491                return None;
17492            }
17493            Err(i) => {
17494                self.find_all_references_task_sources.insert(i, head_anchor);
17495            }
17496        }
17497
17498        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17499        let workspace = self.workspace()?;
17500        let project = workspace.read(cx).project().clone();
17501        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17502        Some(cx.spawn_in(window, async move |editor, cx| {
17503            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17504                if let Ok(i) = editor
17505                    .find_all_references_task_sources
17506                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17507                {
17508                    editor.find_all_references_task_sources.remove(i);
17509                }
17510            });
17511
17512            let Some(locations) = references.await? else {
17513                return anyhow::Ok(Navigated::No);
17514            };
17515            let mut locations = cx.update(|_, cx| {
17516                locations
17517                    .into_iter()
17518                    .map(|location| {
17519                        let buffer = location.buffer.read(cx);
17520                        (location.buffer, location.range.to_point(buffer))
17521                    })
17522                    // if special-casing the single-match case, remove ranges
17523                    // that intersect current selection
17524                    .filter(|(location_buffer, location)| {
17525                        if always_open_multibuffer || &buffer != location_buffer {
17526                            return true;
17527                        }
17528
17529                        !location.contains_inclusive(&selection_point.range())
17530                    })
17531                    .into_group_map()
17532            })?;
17533            if locations.is_empty() {
17534                return anyhow::Ok(Navigated::No);
17535            }
17536            for ranges in locations.values_mut() {
17537                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17538                ranges.dedup();
17539            }
17540            let mut num_locations = 0;
17541            for ranges in locations.values_mut() {
17542                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17543                ranges.dedup();
17544                num_locations += ranges.len();
17545            }
17546
17547            if num_locations == 1 && !always_open_multibuffer {
17548                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17549                let target_range = target_ranges.first().unwrap().clone();
17550
17551                return editor.update_in(cx, |editor, window, cx| {
17552                    let range = target_range.to_point(target_buffer.read(cx));
17553                    let range = editor.range_for_match(&range);
17554                    let range = range.start..range.start;
17555
17556                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17557                        editor.go_to_singleton_buffer_range(range, window, cx);
17558                    } else {
17559                        let pane = workspace.read(cx).active_pane().clone();
17560                        window.defer(cx, move |window, cx| {
17561                            let target_editor: Entity<Self> =
17562                                workspace.update(cx, |workspace, cx| {
17563                                    let pane = workspace.active_pane().clone();
17564
17565                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17566                                    let keep_old_preview = preview_tabs_settings
17567                                        .enable_keep_preview_on_code_navigation;
17568                                    let allow_new_preview = preview_tabs_settings
17569                                        .enable_preview_file_from_code_navigation;
17570
17571                                    workspace.open_project_item(
17572                                        pane,
17573                                        target_buffer.clone(),
17574                                        true,
17575                                        true,
17576                                        keep_old_preview,
17577                                        allow_new_preview,
17578                                        window,
17579                                        cx,
17580                                    )
17581                                });
17582                            target_editor.update(cx, |target_editor, cx| {
17583                                // When selecting a definition in a different buffer, disable the nav history
17584                                // to avoid creating a history entry at the previous cursor location.
17585                                pane.update(cx, |pane, _| pane.disable_history());
17586                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17587                                pane.update(cx, |pane, _| pane.enable_history());
17588                            });
17589                        });
17590                    }
17591                    Navigated::No
17592                });
17593            }
17594
17595            workspace.update_in(cx, |workspace, window, cx| {
17596                let target = locations
17597                    .iter()
17598                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17599                    .map(|(buffer, location)| {
17600                        buffer
17601                            .read(cx)
17602                            .text_for_range(location.clone())
17603                            .collect::<String>()
17604                    })
17605                    .filter(|text| !text.contains('\n'))
17606                    .unique()
17607                    .take(3)
17608                    .join(", ");
17609                let title = if target.is_empty() {
17610                    "References".to_owned()
17611                } else {
17612                    format!("References to {target}")
17613                };
17614                let allow_preview = PreviewTabsSettings::get_global(cx)
17615                    .enable_preview_multibuffer_from_code_navigation;
17616                Self::open_locations_in_multibuffer(
17617                    workspace,
17618                    locations,
17619                    title,
17620                    false,
17621                    allow_preview,
17622                    MultibufferSelectionMode::First,
17623                    window,
17624                    cx,
17625                );
17626                Navigated::Yes
17627            })
17628        }))
17629    }
17630
17631    /// Opens a multibuffer with the given project locations in it.
17632    pub fn open_locations_in_multibuffer(
17633        workspace: &mut Workspace,
17634        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17635        title: String,
17636        split: bool,
17637        allow_preview: bool,
17638        multibuffer_selection_mode: MultibufferSelectionMode,
17639        window: &mut Window,
17640        cx: &mut Context<Workspace>,
17641    ) {
17642        if locations.is_empty() {
17643            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17644            return;
17645        }
17646
17647        let capability = workspace.project().read(cx).capability();
17648        let mut ranges = <Vec<Range<Anchor>>>::new();
17649
17650        // a key to find existing multibuffer editors with the same set of locations
17651        // to prevent us from opening more and more multibuffer tabs for searches and the like
17652        let mut key = (title.clone(), vec![]);
17653        let excerpt_buffer = cx.new(|cx| {
17654            let key = &mut key.1;
17655            let mut multibuffer = MultiBuffer::new(capability);
17656            for (buffer, mut ranges_for_buffer) in locations {
17657                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17658                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17659                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17660                    PathKey::for_buffer(&buffer, cx),
17661                    buffer.clone(),
17662                    ranges_for_buffer,
17663                    multibuffer_context_lines(cx),
17664                    cx,
17665                );
17666                ranges.extend(new_ranges)
17667            }
17668
17669            multibuffer.with_title(title)
17670        });
17671        let existing = workspace.active_pane().update(cx, |pane, cx| {
17672            pane.items()
17673                .filter_map(|item| item.downcast::<Editor>())
17674                .find(|editor| {
17675                    editor
17676                        .read(cx)
17677                        .lookup_key
17678                        .as_ref()
17679                        .and_then(|it| {
17680                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17681                        })
17682                        .is_some_and(|it| *it == key)
17683                })
17684        });
17685        let was_existing = existing.is_some();
17686        let editor = existing.unwrap_or_else(|| {
17687            cx.new(|cx| {
17688                let mut editor = Editor::for_multibuffer(
17689                    excerpt_buffer,
17690                    Some(workspace.project().clone()),
17691                    window,
17692                    cx,
17693                );
17694                editor.lookup_key = Some(Box::new(key));
17695                editor
17696            })
17697        });
17698        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17699            MultibufferSelectionMode::First => {
17700                if let Some(first_range) = ranges.first() {
17701                    editor.change_selections(
17702                        SelectionEffects::no_scroll(),
17703                        window,
17704                        cx,
17705                        |selections| {
17706                            selections.clear_disjoint();
17707                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17708                        },
17709                    );
17710                }
17711                editor.highlight_background::<Self>(
17712                    &ranges,
17713                    |_, theme| theme.colors().editor_highlighted_line_background,
17714                    cx,
17715                );
17716            }
17717            MultibufferSelectionMode::All => {
17718                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17719                    selections.clear_disjoint();
17720                    selections.select_anchor_ranges(ranges);
17721                });
17722            }
17723        });
17724
17725        let item = Box::new(editor);
17726
17727        let pane = if split {
17728            workspace.adjacent_pane(window, cx)
17729        } else {
17730            workspace.active_pane().clone()
17731        };
17732        let activate_pane = split;
17733
17734        let mut destination_index = None;
17735        pane.update(cx, |pane, cx| {
17736            if allow_preview && !was_existing {
17737                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
17738            }
17739            if was_existing && !allow_preview {
17740                pane.unpreview_item_if_preview(item.item_id());
17741            }
17742            pane.add_item(item, activate_pane, true, destination_index, window, cx);
17743        });
17744    }
17745
17746    pub fn rename(
17747        &mut self,
17748        _: &Rename,
17749        window: &mut Window,
17750        cx: &mut Context<Self>,
17751    ) -> Option<Task<Result<()>>> {
17752        use language::ToOffset as _;
17753
17754        let provider = self.semantics_provider.clone()?;
17755        let selection = self.selections.newest_anchor().clone();
17756        let (cursor_buffer, cursor_buffer_position) = self
17757            .buffer
17758            .read(cx)
17759            .text_anchor_for_position(selection.head(), cx)?;
17760        let (tail_buffer, cursor_buffer_position_end) = self
17761            .buffer
17762            .read(cx)
17763            .text_anchor_for_position(selection.tail(), cx)?;
17764        if tail_buffer != cursor_buffer {
17765            return None;
17766        }
17767
17768        let snapshot = cursor_buffer.read(cx).snapshot();
17769        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17770        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17771        let prepare_rename = provider
17772            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17773            .unwrap_or_else(|| Task::ready(Ok(None)));
17774        drop(snapshot);
17775
17776        Some(cx.spawn_in(window, async move |this, cx| {
17777            let rename_range = if let Some(range) = prepare_rename.await? {
17778                Some(range)
17779            } else {
17780                this.update(cx, |this, cx| {
17781                    let buffer = this.buffer.read(cx).snapshot(cx);
17782                    let mut buffer_highlights = this
17783                        .document_highlights_for_position(selection.head(), &buffer)
17784                        .filter(|highlight| {
17785                            highlight.start.excerpt_id == selection.head().excerpt_id
17786                                && highlight.end.excerpt_id == selection.head().excerpt_id
17787                        });
17788                    buffer_highlights
17789                        .next()
17790                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17791                })?
17792            };
17793            if let Some(rename_range) = rename_range {
17794                this.update_in(cx, |this, window, cx| {
17795                    let snapshot = cursor_buffer.read(cx).snapshot();
17796                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17797                    let cursor_offset_in_rename_range =
17798                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17799                    let cursor_offset_in_rename_range_end =
17800                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17801
17802                    this.take_rename(false, window, cx);
17803                    let buffer = this.buffer.read(cx).read(cx);
17804                    let cursor_offset = selection.head().to_offset(&buffer);
17805                    let rename_start =
17806                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17807                    let rename_end = rename_start + rename_buffer_range.len();
17808                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17809                    let mut old_highlight_id = None;
17810                    let old_name: Arc<str> = buffer
17811                        .chunks(rename_start..rename_end, true)
17812                        .map(|chunk| {
17813                            if old_highlight_id.is_none() {
17814                                old_highlight_id = chunk.syntax_highlight_id;
17815                            }
17816                            chunk.text
17817                        })
17818                        .collect::<String>()
17819                        .into();
17820
17821                    drop(buffer);
17822
17823                    // Position the selection in the rename editor so that it matches the current selection.
17824                    this.show_local_selections = false;
17825                    let rename_editor = cx.new(|cx| {
17826                        let mut editor = Editor::single_line(window, cx);
17827                        editor.buffer.update(cx, |buffer, cx| {
17828                            buffer.edit(
17829                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17830                                None,
17831                                cx,
17832                            )
17833                        });
17834                        let cursor_offset_in_rename_range =
17835                            MultiBufferOffset(cursor_offset_in_rename_range);
17836                        let cursor_offset_in_rename_range_end =
17837                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17838                        let rename_selection_range = match cursor_offset_in_rename_range
17839                            .cmp(&cursor_offset_in_rename_range_end)
17840                        {
17841                            Ordering::Equal => {
17842                                editor.select_all(&SelectAll, window, cx);
17843                                return editor;
17844                            }
17845                            Ordering::Less => {
17846                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17847                            }
17848                            Ordering::Greater => {
17849                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17850                            }
17851                        };
17852                        if rename_selection_range.end.0 > old_name.len() {
17853                            editor.select_all(&SelectAll, window, cx);
17854                        } else {
17855                            editor.change_selections(Default::default(), window, cx, |s| {
17856                                s.select_ranges([rename_selection_range]);
17857                            });
17858                        }
17859                        editor
17860                    });
17861                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17862                        if e == &EditorEvent::Focused {
17863                            cx.emit(EditorEvent::FocusedIn)
17864                        }
17865                    })
17866                    .detach();
17867
17868                    let write_highlights =
17869                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17870                    let read_highlights =
17871                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17872                    let ranges = write_highlights
17873                        .iter()
17874                        .flat_map(|(_, ranges)| ranges.iter())
17875                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17876                        .cloned()
17877                        .collect();
17878
17879                    this.highlight_text::<Rename>(
17880                        ranges,
17881                        HighlightStyle {
17882                            fade_out: Some(0.6),
17883                            ..Default::default()
17884                        },
17885                        cx,
17886                    );
17887                    let rename_focus_handle = rename_editor.focus_handle(cx);
17888                    window.focus(&rename_focus_handle);
17889                    let block_id = this.insert_blocks(
17890                        [BlockProperties {
17891                            style: BlockStyle::Flex,
17892                            placement: BlockPlacement::Below(range.start),
17893                            height: Some(1),
17894                            render: Arc::new({
17895                                let rename_editor = rename_editor.clone();
17896                                move |cx: &mut BlockContext| {
17897                                    let mut text_style = cx.editor_style.text.clone();
17898                                    if let Some(highlight_style) = old_highlight_id
17899                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17900                                    {
17901                                        text_style = text_style.highlight(highlight_style);
17902                                    }
17903                                    div()
17904                                        .block_mouse_except_scroll()
17905                                        .pl(cx.anchor_x)
17906                                        .child(EditorElement::new(
17907                                            &rename_editor,
17908                                            EditorStyle {
17909                                                background: cx.theme().system().transparent,
17910                                                local_player: cx.editor_style.local_player,
17911                                                text: text_style,
17912                                                scrollbar_width: cx.editor_style.scrollbar_width,
17913                                                syntax: cx.editor_style.syntax.clone(),
17914                                                status: cx.editor_style.status.clone(),
17915                                                inlay_hints_style: HighlightStyle {
17916                                                    font_weight: Some(FontWeight::BOLD),
17917                                                    ..make_inlay_hints_style(cx.app)
17918                                                },
17919                                                edit_prediction_styles: make_suggestion_styles(
17920                                                    cx.app,
17921                                                ),
17922                                                ..EditorStyle::default()
17923                                            },
17924                                        ))
17925                                        .into_any_element()
17926                                }
17927                            }),
17928                            priority: 0,
17929                        }],
17930                        Some(Autoscroll::fit()),
17931                        cx,
17932                    )[0];
17933                    this.pending_rename = Some(RenameState {
17934                        range,
17935                        old_name,
17936                        editor: rename_editor,
17937                        block_id,
17938                    });
17939                })?;
17940            }
17941
17942            Ok(())
17943        }))
17944    }
17945
17946    pub fn confirm_rename(
17947        &mut self,
17948        _: &ConfirmRename,
17949        window: &mut Window,
17950        cx: &mut Context<Self>,
17951    ) -> Option<Task<Result<()>>> {
17952        let rename = self.take_rename(false, window, cx)?;
17953        let workspace = self.workspace()?.downgrade();
17954        let (buffer, start) = self
17955            .buffer
17956            .read(cx)
17957            .text_anchor_for_position(rename.range.start, cx)?;
17958        let (end_buffer, _) = self
17959            .buffer
17960            .read(cx)
17961            .text_anchor_for_position(rename.range.end, cx)?;
17962        if buffer != end_buffer {
17963            return None;
17964        }
17965
17966        let old_name = rename.old_name;
17967        let new_name = rename.editor.read(cx).text(cx);
17968
17969        let rename = self.semantics_provider.as_ref()?.perform_rename(
17970            &buffer,
17971            start,
17972            new_name.clone(),
17973            cx,
17974        )?;
17975
17976        Some(cx.spawn_in(window, async move |editor, cx| {
17977            let project_transaction = rename.await?;
17978            Self::open_project_transaction(
17979                &editor,
17980                workspace,
17981                project_transaction,
17982                format!("Rename: {}{}", old_name, new_name),
17983                cx,
17984            )
17985            .await?;
17986
17987            editor.update(cx, |editor, cx| {
17988                editor.refresh_document_highlights(cx);
17989            })?;
17990            Ok(())
17991        }))
17992    }
17993
17994    fn take_rename(
17995        &mut self,
17996        moving_cursor: bool,
17997        window: &mut Window,
17998        cx: &mut Context<Self>,
17999    ) -> Option<RenameState> {
18000        let rename = self.pending_rename.take()?;
18001        if rename.editor.focus_handle(cx).is_focused(window) {
18002            window.focus(&self.focus_handle);
18003        }
18004
18005        self.remove_blocks(
18006            [rename.block_id].into_iter().collect(),
18007            Some(Autoscroll::fit()),
18008            cx,
18009        );
18010        self.clear_highlights::<Rename>(cx);
18011        self.show_local_selections = true;
18012
18013        if moving_cursor {
18014            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18015                editor
18016                    .selections
18017                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18018                    .head()
18019            });
18020
18021            // Update the selection to match the position of the selection inside
18022            // the rename editor.
18023            let snapshot = self.buffer.read(cx).read(cx);
18024            let rename_range = rename.range.to_offset(&snapshot);
18025            let cursor_in_editor = snapshot
18026                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18027                .min(rename_range.end);
18028            drop(snapshot);
18029
18030            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18031                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18032            });
18033        } else {
18034            self.refresh_document_highlights(cx);
18035        }
18036
18037        Some(rename)
18038    }
18039
18040    pub fn pending_rename(&self) -> Option<&RenameState> {
18041        self.pending_rename.as_ref()
18042    }
18043
18044    fn format(
18045        &mut self,
18046        _: &Format,
18047        window: &mut Window,
18048        cx: &mut Context<Self>,
18049    ) -> Option<Task<Result<()>>> {
18050        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18051
18052        let project = match &self.project {
18053            Some(project) => project.clone(),
18054            None => return None,
18055        };
18056
18057        Some(self.perform_format(
18058            project,
18059            FormatTrigger::Manual,
18060            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18061            window,
18062            cx,
18063        ))
18064    }
18065
18066    fn format_selections(
18067        &mut self,
18068        _: &FormatSelections,
18069        window: &mut Window,
18070        cx: &mut Context<Self>,
18071    ) -> Option<Task<Result<()>>> {
18072        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18073
18074        let project = match &self.project {
18075            Some(project) => project.clone(),
18076            None => return None,
18077        };
18078
18079        let ranges = self
18080            .selections
18081            .all_adjusted(&self.display_snapshot(cx))
18082            .into_iter()
18083            .map(|selection| selection.range())
18084            .collect_vec();
18085
18086        Some(self.perform_format(
18087            project,
18088            FormatTrigger::Manual,
18089            FormatTarget::Ranges(ranges),
18090            window,
18091            cx,
18092        ))
18093    }
18094
18095    fn perform_format(
18096        &mut self,
18097        project: Entity<Project>,
18098        trigger: FormatTrigger,
18099        target: FormatTarget,
18100        window: &mut Window,
18101        cx: &mut Context<Self>,
18102    ) -> Task<Result<()>> {
18103        let buffer = self.buffer.clone();
18104        let (buffers, target) = match target {
18105            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18106            FormatTarget::Ranges(selection_ranges) => {
18107                let multi_buffer = buffer.read(cx);
18108                let snapshot = multi_buffer.read(cx);
18109                let mut buffers = HashSet::default();
18110                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18111                    BTreeMap::new();
18112                for selection_range in selection_ranges {
18113                    for (buffer, buffer_range, _) in
18114                        snapshot.range_to_buffer_ranges(selection_range)
18115                    {
18116                        let buffer_id = buffer.remote_id();
18117                        let start = buffer.anchor_before(buffer_range.start);
18118                        let end = buffer.anchor_after(buffer_range.end);
18119                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18120                        buffer_id_to_ranges
18121                            .entry(buffer_id)
18122                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18123                            .or_insert_with(|| vec![start..end]);
18124                    }
18125                }
18126                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18127            }
18128        };
18129
18130        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18131        let selections_prev = transaction_id_prev
18132            .and_then(|transaction_id_prev| {
18133                // default to selections as they were after the last edit, if we have them,
18134                // instead of how they are now.
18135                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18136                // will take you back to where you made the last edit, instead of staying where you scrolled
18137                self.selection_history
18138                    .transaction(transaction_id_prev)
18139                    .map(|t| t.0.clone())
18140            })
18141            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18142
18143        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18144        let format = project.update(cx, |project, cx| {
18145            project.format(buffers, target, true, trigger, cx)
18146        });
18147
18148        cx.spawn_in(window, async move |editor, cx| {
18149            let transaction = futures::select_biased! {
18150                transaction = format.log_err().fuse() => transaction,
18151                () = timeout => {
18152                    log::warn!("timed out waiting for formatting");
18153                    None
18154                }
18155            };
18156
18157            buffer
18158                .update(cx, |buffer, cx| {
18159                    if let Some(transaction) = transaction
18160                        && !buffer.is_singleton()
18161                    {
18162                        buffer.push_transaction(&transaction.0, cx);
18163                    }
18164                    cx.notify();
18165                })
18166                .ok();
18167
18168            if let Some(transaction_id_now) =
18169                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18170            {
18171                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18172                if has_new_transaction {
18173                    _ = editor.update(cx, |editor, _| {
18174                        editor
18175                            .selection_history
18176                            .insert_transaction(transaction_id_now, selections_prev);
18177                    });
18178                }
18179            }
18180
18181            Ok(())
18182        })
18183    }
18184
18185    fn organize_imports(
18186        &mut self,
18187        _: &OrganizeImports,
18188        window: &mut Window,
18189        cx: &mut Context<Self>,
18190    ) -> Option<Task<Result<()>>> {
18191        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18192        let project = match &self.project {
18193            Some(project) => project.clone(),
18194            None => return None,
18195        };
18196        Some(self.perform_code_action_kind(
18197            project,
18198            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18199            window,
18200            cx,
18201        ))
18202    }
18203
18204    fn perform_code_action_kind(
18205        &mut self,
18206        project: Entity<Project>,
18207        kind: CodeActionKind,
18208        window: &mut Window,
18209        cx: &mut Context<Self>,
18210    ) -> Task<Result<()>> {
18211        let buffer = self.buffer.clone();
18212        let buffers = buffer.read(cx).all_buffers();
18213        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18214        let apply_action = project.update(cx, |project, cx| {
18215            project.apply_code_action_kind(buffers, kind, true, cx)
18216        });
18217        cx.spawn_in(window, async move |_, cx| {
18218            let transaction = futures::select_biased! {
18219                () = timeout => {
18220                    log::warn!("timed out waiting for executing code action");
18221                    None
18222                }
18223                transaction = apply_action.log_err().fuse() => transaction,
18224            };
18225            buffer
18226                .update(cx, |buffer, cx| {
18227                    // check if we need this
18228                    if let Some(transaction) = transaction
18229                        && !buffer.is_singleton()
18230                    {
18231                        buffer.push_transaction(&transaction.0, cx);
18232                    }
18233                    cx.notify();
18234                })
18235                .ok();
18236            Ok(())
18237        })
18238    }
18239
18240    pub fn restart_language_server(
18241        &mut self,
18242        _: &RestartLanguageServer,
18243        _: &mut Window,
18244        cx: &mut Context<Self>,
18245    ) {
18246        if let Some(project) = self.project.clone() {
18247            self.buffer.update(cx, |multi_buffer, cx| {
18248                project.update(cx, |project, cx| {
18249                    project.restart_language_servers_for_buffers(
18250                        multi_buffer.all_buffers().into_iter().collect(),
18251                        HashSet::default(),
18252                        cx,
18253                    );
18254                });
18255            })
18256        }
18257    }
18258
18259    pub fn stop_language_server(
18260        &mut self,
18261        _: &StopLanguageServer,
18262        _: &mut Window,
18263        cx: &mut Context<Self>,
18264    ) {
18265        if let Some(project) = self.project.clone() {
18266            self.buffer.update(cx, |multi_buffer, cx| {
18267                project.update(cx, |project, cx| {
18268                    project.stop_language_servers_for_buffers(
18269                        multi_buffer.all_buffers().into_iter().collect(),
18270                        HashSet::default(),
18271                        cx,
18272                    );
18273                });
18274            });
18275            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18276        }
18277    }
18278
18279    fn cancel_language_server_work(
18280        workspace: &mut Workspace,
18281        _: &actions::CancelLanguageServerWork,
18282        _: &mut Window,
18283        cx: &mut Context<Workspace>,
18284    ) {
18285        let project = workspace.project();
18286        let buffers = workspace
18287            .active_item(cx)
18288            .and_then(|item| item.act_as::<Editor>(cx))
18289            .map_or(HashSet::default(), |editor| {
18290                editor.read(cx).buffer.read(cx).all_buffers()
18291            });
18292        project.update(cx, |project, cx| {
18293            project.cancel_language_server_work_for_buffers(buffers, cx);
18294        });
18295    }
18296
18297    fn show_character_palette(
18298        &mut self,
18299        _: &ShowCharacterPalette,
18300        window: &mut Window,
18301        _: &mut Context<Self>,
18302    ) {
18303        window.show_character_palette();
18304    }
18305
18306    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18307        if !self.diagnostics_enabled() {
18308            return;
18309        }
18310
18311        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18312            let buffer = self.buffer.read(cx).snapshot(cx);
18313            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18314            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18315            let is_valid = buffer
18316                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18317                .any(|entry| {
18318                    entry.diagnostic.is_primary
18319                        && !entry.range.is_empty()
18320                        && entry.range.start == primary_range_start
18321                        && entry.diagnostic.message == active_diagnostics.active_message
18322                });
18323
18324            if !is_valid {
18325                self.dismiss_diagnostics(cx);
18326            }
18327        }
18328    }
18329
18330    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18331        match &self.active_diagnostics {
18332            ActiveDiagnostic::Group(group) => Some(group),
18333            _ => None,
18334        }
18335    }
18336
18337    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18338        if !self.diagnostics_enabled() {
18339            return;
18340        }
18341        self.dismiss_diagnostics(cx);
18342        self.active_diagnostics = ActiveDiagnostic::All;
18343    }
18344
18345    fn activate_diagnostics(
18346        &mut self,
18347        buffer_id: BufferId,
18348        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18349        window: &mut Window,
18350        cx: &mut Context<Self>,
18351    ) {
18352        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18353            return;
18354        }
18355        self.dismiss_diagnostics(cx);
18356        let snapshot = self.snapshot(window, cx);
18357        let buffer = self.buffer.read(cx).snapshot(cx);
18358        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18359            return;
18360        };
18361
18362        let diagnostic_group = buffer
18363            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18364            .collect::<Vec<_>>();
18365
18366        let language_registry = self
18367            .project()
18368            .map(|project| project.read(cx).languages().clone());
18369
18370        let blocks = renderer.render_group(
18371            diagnostic_group,
18372            buffer_id,
18373            snapshot,
18374            cx.weak_entity(),
18375            language_registry,
18376            cx,
18377        );
18378
18379        let blocks = self.display_map.update(cx, |display_map, cx| {
18380            display_map.insert_blocks(blocks, cx).into_iter().collect()
18381        });
18382        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18383            active_range: buffer.anchor_before(diagnostic.range.start)
18384                ..buffer.anchor_after(diagnostic.range.end),
18385            active_message: diagnostic.diagnostic.message.clone(),
18386            group_id: diagnostic.diagnostic.group_id,
18387            blocks,
18388        });
18389        cx.notify();
18390    }
18391
18392    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18393        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18394            return;
18395        };
18396
18397        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18398        if let ActiveDiagnostic::Group(group) = prev {
18399            self.display_map.update(cx, |display_map, cx| {
18400                display_map.remove_blocks(group.blocks, cx);
18401            });
18402            cx.notify();
18403        }
18404    }
18405
18406    /// Disable inline diagnostics rendering for this editor.
18407    pub fn disable_inline_diagnostics(&mut self) {
18408        self.inline_diagnostics_enabled = false;
18409        self.inline_diagnostics_update = Task::ready(());
18410        self.inline_diagnostics.clear();
18411    }
18412
18413    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18414        self.diagnostics_enabled = false;
18415        self.dismiss_diagnostics(cx);
18416        self.inline_diagnostics_update = Task::ready(());
18417        self.inline_diagnostics.clear();
18418    }
18419
18420    pub fn disable_word_completions(&mut self) {
18421        self.word_completions_enabled = false;
18422    }
18423
18424    pub fn diagnostics_enabled(&self) -> bool {
18425        self.diagnostics_enabled && self.mode.is_full()
18426    }
18427
18428    pub fn inline_diagnostics_enabled(&self) -> bool {
18429        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18430    }
18431
18432    pub fn show_inline_diagnostics(&self) -> bool {
18433        self.show_inline_diagnostics
18434    }
18435
18436    pub fn toggle_inline_diagnostics(
18437        &mut self,
18438        _: &ToggleInlineDiagnostics,
18439        window: &mut Window,
18440        cx: &mut Context<Editor>,
18441    ) {
18442        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18443        self.refresh_inline_diagnostics(false, window, cx);
18444    }
18445
18446    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18447        self.diagnostics_max_severity = severity;
18448        self.display_map.update(cx, |display_map, _| {
18449            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18450        });
18451    }
18452
18453    pub fn toggle_diagnostics(
18454        &mut self,
18455        _: &ToggleDiagnostics,
18456        window: &mut Window,
18457        cx: &mut Context<Editor>,
18458    ) {
18459        if !self.diagnostics_enabled() {
18460            return;
18461        }
18462
18463        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18464            EditorSettings::get_global(cx)
18465                .diagnostics_max_severity
18466                .filter(|severity| severity != &DiagnosticSeverity::Off)
18467                .unwrap_or(DiagnosticSeverity::Hint)
18468        } else {
18469            DiagnosticSeverity::Off
18470        };
18471        self.set_max_diagnostics_severity(new_severity, cx);
18472        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18473            self.active_diagnostics = ActiveDiagnostic::None;
18474            self.inline_diagnostics_update = Task::ready(());
18475            self.inline_diagnostics.clear();
18476        } else {
18477            self.refresh_inline_diagnostics(false, window, cx);
18478        }
18479
18480        cx.notify();
18481    }
18482
18483    pub fn toggle_minimap(
18484        &mut self,
18485        _: &ToggleMinimap,
18486        window: &mut Window,
18487        cx: &mut Context<Editor>,
18488    ) {
18489        if self.supports_minimap(cx) {
18490            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18491        }
18492    }
18493
18494    fn refresh_inline_diagnostics(
18495        &mut self,
18496        debounce: bool,
18497        window: &mut Window,
18498        cx: &mut Context<Self>,
18499    ) {
18500        let max_severity = ProjectSettings::get_global(cx)
18501            .diagnostics
18502            .inline
18503            .max_severity
18504            .unwrap_or(self.diagnostics_max_severity);
18505
18506        if !self.inline_diagnostics_enabled()
18507            || !self.diagnostics_enabled()
18508            || !self.show_inline_diagnostics
18509            || max_severity == DiagnosticSeverity::Off
18510        {
18511            self.inline_diagnostics_update = Task::ready(());
18512            self.inline_diagnostics.clear();
18513            return;
18514        }
18515
18516        let debounce_ms = ProjectSettings::get_global(cx)
18517            .diagnostics
18518            .inline
18519            .update_debounce_ms;
18520        let debounce = if debounce && debounce_ms > 0 {
18521            Some(Duration::from_millis(debounce_ms))
18522        } else {
18523            None
18524        };
18525        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18526            if let Some(debounce) = debounce {
18527                cx.background_executor().timer(debounce).await;
18528            }
18529            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18530                editor
18531                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18532                    .ok()
18533            }) else {
18534                return;
18535            };
18536
18537            let new_inline_diagnostics = cx
18538                .background_spawn(async move {
18539                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18540                    for diagnostic_entry in
18541                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18542                    {
18543                        let message = diagnostic_entry
18544                            .diagnostic
18545                            .message
18546                            .split_once('\n')
18547                            .map(|(line, _)| line)
18548                            .map(SharedString::new)
18549                            .unwrap_or_else(|| {
18550                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18551                            });
18552                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18553                        let (Ok(i) | Err(i)) = inline_diagnostics
18554                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18555                        inline_diagnostics.insert(
18556                            i,
18557                            (
18558                                start_anchor,
18559                                InlineDiagnostic {
18560                                    message,
18561                                    group_id: diagnostic_entry.diagnostic.group_id,
18562                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18563                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18564                                    severity: diagnostic_entry.diagnostic.severity,
18565                                },
18566                            ),
18567                        );
18568                    }
18569                    inline_diagnostics
18570                })
18571                .await;
18572
18573            editor
18574                .update(cx, |editor, cx| {
18575                    editor.inline_diagnostics = new_inline_diagnostics;
18576                    cx.notify();
18577                })
18578                .ok();
18579        });
18580    }
18581
18582    fn pull_diagnostics(
18583        &mut self,
18584        buffer_id: Option<BufferId>,
18585        window: &Window,
18586        cx: &mut Context<Self>,
18587    ) -> Option<()> {
18588        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18589            return None;
18590        }
18591        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18592            .diagnostics
18593            .lsp_pull_diagnostics;
18594        if !pull_diagnostics_settings.enabled {
18595            return None;
18596        }
18597        let project = self.project()?.downgrade();
18598
18599        let mut edited_buffer_ids = HashSet::default();
18600        let mut edited_worktree_ids = HashSet::default();
18601        let edited_buffers = match buffer_id {
18602            Some(buffer_id) => {
18603                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18604                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18605                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18606                edited_worktree_ids.insert(worktree_id);
18607                vec![buffer]
18608            }
18609            None => self
18610                .buffer()
18611                .read(cx)
18612                .all_buffers()
18613                .into_iter()
18614                .filter(|buffer| {
18615                    let buffer = buffer.read(cx);
18616                    match buffer.file().map(|f| f.worktree_id(cx)) {
18617                        Some(worktree_id) => {
18618                            edited_buffer_ids.insert(buffer.remote_id());
18619                            edited_worktree_ids.insert(worktree_id);
18620                            true
18621                        }
18622                        None => false,
18623                    }
18624                })
18625                .collect::<Vec<_>>(),
18626        };
18627
18628        if edited_buffers.is_empty() {
18629            self.pull_diagnostics_task = Task::ready(());
18630            self.pull_diagnostics_background_task = Task::ready(());
18631            return None;
18632        }
18633
18634        let mut already_used_buffers = HashSet::default();
18635        let related_open_buffers = self
18636            .workspace
18637            .as_ref()
18638            .and_then(|(workspace, _)| workspace.upgrade())
18639            .into_iter()
18640            .flat_map(|workspace| workspace.read(cx).panes())
18641            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18642            .filter(|editor| editor != &cx.entity())
18643            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18644            .filter(|buffer| {
18645                let buffer = buffer.read(cx);
18646                let buffer_id = buffer.remote_id();
18647                if already_used_buffers.insert(buffer_id) {
18648                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18649                        return !edited_buffer_ids.contains(&buffer_id)
18650                            && !edited_worktree_ids.contains(&worktree_id);
18651                    }
18652                }
18653                false
18654            })
18655            .collect::<Vec<_>>();
18656
18657        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18658        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18659            if buffers.is_empty() {
18660                return Task::ready(());
18661            }
18662            let project_weak = project.clone();
18663            cx.spawn_in(window, async move |_, cx| {
18664                cx.background_executor().timer(delay).await;
18665
18666                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18667                    buffers
18668                        .into_iter()
18669                        .filter_map(|buffer| {
18670                            project_weak
18671                                .update(cx, |project, cx| {
18672                                    project.lsp_store().update(cx, |lsp_store, cx| {
18673                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18674                                    })
18675                                })
18676                                .ok()
18677                        })
18678                        .collect::<FuturesUnordered<_>>()
18679                }) else {
18680                    return;
18681                };
18682
18683                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18684                    if let Err(e) = pull_task {
18685                        log::error!("Failed to update project diagnostics: {e:#}");
18686                    }
18687                }
18688            })
18689        };
18690
18691        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18692        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18693
18694        Some(())
18695    }
18696
18697    pub fn set_selections_from_remote(
18698        &mut self,
18699        selections: Vec<Selection<Anchor>>,
18700        pending_selection: Option<Selection<Anchor>>,
18701        window: &mut Window,
18702        cx: &mut Context<Self>,
18703    ) {
18704        let old_cursor_position = self.selections.newest_anchor().head();
18705        self.selections
18706            .change_with(&self.display_snapshot(cx), |s| {
18707                s.select_anchors(selections);
18708                if let Some(pending_selection) = pending_selection {
18709                    s.set_pending(pending_selection, SelectMode::Character);
18710                } else {
18711                    s.clear_pending();
18712                }
18713            });
18714        self.selections_did_change(
18715            false,
18716            &old_cursor_position,
18717            SelectionEffects::default(),
18718            window,
18719            cx,
18720        );
18721    }
18722
18723    pub fn transact(
18724        &mut self,
18725        window: &mut Window,
18726        cx: &mut Context<Self>,
18727        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18728    ) -> Option<TransactionId> {
18729        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18730            this.start_transaction_at(Instant::now(), window, cx);
18731            update(this, window, cx);
18732            this.end_transaction_at(Instant::now(), cx)
18733        })
18734    }
18735
18736    pub fn start_transaction_at(
18737        &mut self,
18738        now: Instant,
18739        window: &mut Window,
18740        cx: &mut Context<Self>,
18741    ) -> Option<TransactionId> {
18742        self.end_selection(window, cx);
18743        if let Some(tx_id) = self
18744            .buffer
18745            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18746        {
18747            self.selection_history
18748                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18749            cx.emit(EditorEvent::TransactionBegun {
18750                transaction_id: tx_id,
18751            });
18752            Some(tx_id)
18753        } else {
18754            None
18755        }
18756    }
18757
18758    pub fn end_transaction_at(
18759        &mut self,
18760        now: Instant,
18761        cx: &mut Context<Self>,
18762    ) -> Option<TransactionId> {
18763        if let Some(transaction_id) = self
18764            .buffer
18765            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18766        {
18767            if let Some((_, end_selections)) =
18768                self.selection_history.transaction_mut(transaction_id)
18769            {
18770                *end_selections = Some(self.selections.disjoint_anchors_arc());
18771            } else {
18772                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18773            }
18774
18775            cx.emit(EditorEvent::Edited { transaction_id });
18776            Some(transaction_id)
18777        } else {
18778            None
18779        }
18780    }
18781
18782    pub fn modify_transaction_selection_history(
18783        &mut self,
18784        transaction_id: TransactionId,
18785        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18786    ) -> bool {
18787        self.selection_history
18788            .transaction_mut(transaction_id)
18789            .map(modify)
18790            .is_some()
18791    }
18792
18793    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18794        if self.selection_mark_mode {
18795            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18796                s.move_with(|_, sel| {
18797                    sel.collapse_to(sel.head(), SelectionGoal::None);
18798                });
18799            })
18800        }
18801        self.selection_mark_mode = true;
18802        cx.notify();
18803    }
18804
18805    pub fn swap_selection_ends(
18806        &mut self,
18807        _: &actions::SwapSelectionEnds,
18808        window: &mut Window,
18809        cx: &mut Context<Self>,
18810    ) {
18811        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18812            s.move_with(|_, sel| {
18813                if sel.start != sel.end {
18814                    sel.reversed = !sel.reversed
18815                }
18816            });
18817        });
18818        self.request_autoscroll(Autoscroll::newest(), cx);
18819        cx.notify();
18820    }
18821
18822    pub fn toggle_focus(
18823        workspace: &mut Workspace,
18824        _: &actions::ToggleFocus,
18825        window: &mut Window,
18826        cx: &mut Context<Workspace>,
18827    ) {
18828        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18829            return;
18830        };
18831        workspace.activate_item(&item, true, true, window, cx);
18832    }
18833
18834    pub fn toggle_fold(
18835        &mut self,
18836        _: &actions::ToggleFold,
18837        window: &mut Window,
18838        cx: &mut Context<Self>,
18839    ) {
18840        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18841            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18842            let selection = self.selections.newest::<Point>(&display_map);
18843
18844            let range = if selection.is_empty() {
18845                let point = selection.head().to_display_point(&display_map);
18846                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18847                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18848                    .to_point(&display_map);
18849                start..end
18850            } else {
18851                selection.range()
18852            };
18853            if display_map.folds_in_range(range).next().is_some() {
18854                self.unfold_lines(&Default::default(), window, cx)
18855            } else {
18856                self.fold(&Default::default(), window, cx)
18857            }
18858        } else {
18859            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18860            let buffer_ids: HashSet<_> = self
18861                .selections
18862                .disjoint_anchor_ranges()
18863                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18864                .collect();
18865
18866            let should_unfold = buffer_ids
18867                .iter()
18868                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18869
18870            for buffer_id in buffer_ids {
18871                if should_unfold {
18872                    self.unfold_buffer(buffer_id, cx);
18873                } else {
18874                    self.fold_buffer(buffer_id, cx);
18875                }
18876            }
18877        }
18878    }
18879
18880    pub fn toggle_fold_recursive(
18881        &mut self,
18882        _: &actions::ToggleFoldRecursive,
18883        window: &mut Window,
18884        cx: &mut Context<Self>,
18885    ) {
18886        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18887
18888        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18889        let range = if selection.is_empty() {
18890            let point = selection.head().to_display_point(&display_map);
18891            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18892            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18893                .to_point(&display_map);
18894            start..end
18895        } else {
18896            selection.range()
18897        };
18898        if display_map.folds_in_range(range).next().is_some() {
18899            self.unfold_recursive(&Default::default(), window, cx)
18900        } else {
18901            self.fold_recursive(&Default::default(), window, cx)
18902        }
18903    }
18904
18905    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18906        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18907            let mut to_fold = Vec::new();
18908            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18909            let selections = self.selections.all_adjusted(&display_map);
18910
18911            for selection in selections {
18912                let range = selection.range().sorted();
18913                let buffer_start_row = range.start.row;
18914
18915                if range.start.row != range.end.row {
18916                    let mut found = false;
18917                    let mut row = range.start.row;
18918                    while row <= range.end.row {
18919                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18920                        {
18921                            found = true;
18922                            row = crease.range().end.row + 1;
18923                            to_fold.push(crease);
18924                        } else {
18925                            row += 1
18926                        }
18927                    }
18928                    if found {
18929                        continue;
18930                    }
18931                }
18932
18933                for row in (0..=range.start.row).rev() {
18934                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18935                        && crease.range().end.row >= buffer_start_row
18936                    {
18937                        to_fold.push(crease);
18938                        if row <= range.start.row {
18939                            break;
18940                        }
18941                    }
18942                }
18943            }
18944
18945            self.fold_creases(to_fold, true, window, cx);
18946        } else {
18947            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18948            let buffer_ids = self
18949                .selections
18950                .disjoint_anchor_ranges()
18951                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18952                .collect::<HashSet<_>>();
18953            for buffer_id in buffer_ids {
18954                self.fold_buffer(buffer_id, cx);
18955            }
18956        }
18957    }
18958
18959    pub fn toggle_fold_all(
18960        &mut self,
18961        _: &actions::ToggleFoldAll,
18962        window: &mut Window,
18963        cx: &mut Context<Self>,
18964    ) {
18965        if self.buffer.read(cx).is_singleton() {
18966            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18967            let has_folds = display_map
18968                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
18969                .next()
18970                .is_some();
18971
18972            if has_folds {
18973                self.unfold_all(&actions::UnfoldAll, window, cx);
18974            } else {
18975                self.fold_all(&actions::FoldAll, window, cx);
18976            }
18977        } else {
18978            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18979            let should_unfold = buffer_ids
18980                .iter()
18981                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18982
18983            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18984                editor
18985                    .update_in(cx, |editor, _, cx| {
18986                        for buffer_id in buffer_ids {
18987                            if should_unfold {
18988                                editor.unfold_buffer(buffer_id, cx);
18989                            } else {
18990                                editor.fold_buffer(buffer_id, cx);
18991                            }
18992                        }
18993                    })
18994                    .ok();
18995            });
18996        }
18997    }
18998
18999    fn fold_at_level(
19000        &mut self,
19001        fold_at: &FoldAtLevel,
19002        window: &mut Window,
19003        cx: &mut Context<Self>,
19004    ) {
19005        if !self.buffer.read(cx).is_singleton() {
19006            return;
19007        }
19008
19009        let fold_at_level = fold_at.0;
19010        let snapshot = self.buffer.read(cx).snapshot(cx);
19011        let mut to_fold = Vec::new();
19012        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19013
19014        let row_ranges_to_keep: Vec<Range<u32>> = self
19015            .selections
19016            .all::<Point>(&self.display_snapshot(cx))
19017            .into_iter()
19018            .map(|sel| sel.start.row..sel.end.row)
19019            .collect();
19020
19021        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19022            while start_row < end_row {
19023                match self
19024                    .snapshot(window, cx)
19025                    .crease_for_buffer_row(MultiBufferRow(start_row))
19026                {
19027                    Some(crease) => {
19028                        let nested_start_row = crease.range().start.row + 1;
19029                        let nested_end_row = crease.range().end.row;
19030
19031                        if current_level < fold_at_level {
19032                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19033                        } else if current_level == fold_at_level {
19034                            // Fold iff there is no selection completely contained within the fold region
19035                            if !row_ranges_to_keep.iter().any(|selection| {
19036                                selection.end >= nested_start_row
19037                                    && selection.start <= nested_end_row
19038                            }) {
19039                                to_fold.push(crease);
19040                            }
19041                        }
19042
19043                        start_row = nested_end_row + 1;
19044                    }
19045                    None => start_row += 1,
19046                }
19047            }
19048        }
19049
19050        self.fold_creases(to_fold, true, window, cx);
19051    }
19052
19053    pub fn fold_at_level_1(
19054        &mut self,
19055        _: &actions::FoldAtLevel1,
19056        window: &mut Window,
19057        cx: &mut Context<Self>,
19058    ) {
19059        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19060    }
19061
19062    pub fn fold_at_level_2(
19063        &mut self,
19064        _: &actions::FoldAtLevel2,
19065        window: &mut Window,
19066        cx: &mut Context<Self>,
19067    ) {
19068        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19069    }
19070
19071    pub fn fold_at_level_3(
19072        &mut self,
19073        _: &actions::FoldAtLevel3,
19074        window: &mut Window,
19075        cx: &mut Context<Self>,
19076    ) {
19077        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19078    }
19079
19080    pub fn fold_at_level_4(
19081        &mut self,
19082        _: &actions::FoldAtLevel4,
19083        window: &mut Window,
19084        cx: &mut Context<Self>,
19085    ) {
19086        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19087    }
19088
19089    pub fn fold_at_level_5(
19090        &mut self,
19091        _: &actions::FoldAtLevel5,
19092        window: &mut Window,
19093        cx: &mut Context<Self>,
19094    ) {
19095        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19096    }
19097
19098    pub fn fold_at_level_6(
19099        &mut self,
19100        _: &actions::FoldAtLevel6,
19101        window: &mut Window,
19102        cx: &mut Context<Self>,
19103    ) {
19104        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19105    }
19106
19107    pub fn fold_at_level_7(
19108        &mut self,
19109        _: &actions::FoldAtLevel7,
19110        window: &mut Window,
19111        cx: &mut Context<Self>,
19112    ) {
19113        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19114    }
19115
19116    pub fn fold_at_level_8(
19117        &mut self,
19118        _: &actions::FoldAtLevel8,
19119        window: &mut Window,
19120        cx: &mut Context<Self>,
19121    ) {
19122        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19123    }
19124
19125    pub fn fold_at_level_9(
19126        &mut self,
19127        _: &actions::FoldAtLevel9,
19128        window: &mut Window,
19129        cx: &mut Context<Self>,
19130    ) {
19131        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19132    }
19133
19134    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19135        if self.buffer.read(cx).is_singleton() {
19136            let mut fold_ranges = Vec::new();
19137            let snapshot = self.buffer.read(cx).snapshot(cx);
19138
19139            for row in 0..snapshot.max_row().0 {
19140                if let Some(foldable_range) = self
19141                    .snapshot(window, cx)
19142                    .crease_for_buffer_row(MultiBufferRow(row))
19143                {
19144                    fold_ranges.push(foldable_range);
19145                }
19146            }
19147
19148            self.fold_creases(fold_ranges, true, window, cx);
19149        } else {
19150            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19151                editor
19152                    .update_in(cx, |editor, _, cx| {
19153                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19154                            editor.fold_buffer(buffer_id, cx);
19155                        }
19156                    })
19157                    .ok();
19158            });
19159        }
19160    }
19161
19162    pub fn fold_function_bodies(
19163        &mut self,
19164        _: &actions::FoldFunctionBodies,
19165        window: &mut Window,
19166        cx: &mut Context<Self>,
19167    ) {
19168        let snapshot = self.buffer.read(cx).snapshot(cx);
19169
19170        let ranges = snapshot
19171            .text_object_ranges(
19172                MultiBufferOffset(0)..snapshot.len(),
19173                TreeSitterOptions::default(),
19174            )
19175            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19176            .collect::<Vec<_>>();
19177
19178        let creases = ranges
19179            .into_iter()
19180            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19181            .collect();
19182
19183        self.fold_creases(creases, true, window, cx);
19184    }
19185
19186    pub fn fold_recursive(
19187        &mut self,
19188        _: &actions::FoldRecursive,
19189        window: &mut Window,
19190        cx: &mut Context<Self>,
19191    ) {
19192        let mut to_fold = Vec::new();
19193        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19194        let selections = self.selections.all_adjusted(&display_map);
19195
19196        for selection in selections {
19197            let range = selection.range().sorted();
19198            let buffer_start_row = range.start.row;
19199
19200            if range.start.row != range.end.row {
19201                let mut found = false;
19202                for row in range.start.row..=range.end.row {
19203                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19204                        found = true;
19205                        to_fold.push(crease);
19206                    }
19207                }
19208                if found {
19209                    continue;
19210                }
19211            }
19212
19213            for row in (0..=range.start.row).rev() {
19214                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19215                    if crease.range().end.row >= buffer_start_row {
19216                        to_fold.push(crease);
19217                    } else {
19218                        break;
19219                    }
19220                }
19221            }
19222        }
19223
19224        self.fold_creases(to_fold, true, window, cx);
19225    }
19226
19227    pub fn fold_at(
19228        &mut self,
19229        buffer_row: MultiBufferRow,
19230        window: &mut Window,
19231        cx: &mut Context<Self>,
19232    ) {
19233        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19234
19235        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19236            let autoscroll = self
19237                .selections
19238                .all::<Point>(&display_map)
19239                .iter()
19240                .any(|selection| crease.range().overlaps(&selection.range()));
19241
19242            self.fold_creases(vec![crease], autoscroll, window, cx);
19243        }
19244    }
19245
19246    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19247        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19248            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19249            let buffer = display_map.buffer_snapshot();
19250            let selections = self.selections.all::<Point>(&display_map);
19251            let ranges = selections
19252                .iter()
19253                .map(|s| {
19254                    let range = s.display_range(&display_map).sorted();
19255                    let mut start = range.start.to_point(&display_map);
19256                    let mut end = range.end.to_point(&display_map);
19257                    start.column = 0;
19258                    end.column = buffer.line_len(MultiBufferRow(end.row));
19259                    start..end
19260                })
19261                .collect::<Vec<_>>();
19262
19263            self.unfold_ranges(&ranges, true, true, cx);
19264        } else {
19265            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19266            let buffer_ids = self
19267                .selections
19268                .disjoint_anchor_ranges()
19269                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19270                .collect::<HashSet<_>>();
19271            for buffer_id in buffer_ids {
19272                self.unfold_buffer(buffer_id, cx);
19273            }
19274        }
19275    }
19276
19277    pub fn unfold_recursive(
19278        &mut self,
19279        _: &UnfoldRecursive,
19280        _window: &mut Window,
19281        cx: &mut Context<Self>,
19282    ) {
19283        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19284        let selections = self.selections.all::<Point>(&display_map);
19285        let ranges = selections
19286            .iter()
19287            .map(|s| {
19288                let mut range = s.display_range(&display_map).sorted();
19289                *range.start.column_mut() = 0;
19290                *range.end.column_mut() = display_map.line_len(range.end.row());
19291                let start = range.start.to_point(&display_map);
19292                let end = range.end.to_point(&display_map);
19293                start..end
19294            })
19295            .collect::<Vec<_>>();
19296
19297        self.unfold_ranges(&ranges, true, true, cx);
19298    }
19299
19300    pub fn unfold_at(
19301        &mut self,
19302        buffer_row: MultiBufferRow,
19303        _window: &mut Window,
19304        cx: &mut Context<Self>,
19305    ) {
19306        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19307
19308        let intersection_range = Point::new(buffer_row.0, 0)
19309            ..Point::new(
19310                buffer_row.0,
19311                display_map.buffer_snapshot().line_len(buffer_row),
19312            );
19313
19314        let autoscroll = self
19315            .selections
19316            .all::<Point>(&display_map)
19317            .iter()
19318            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19319
19320        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19321    }
19322
19323    pub fn unfold_all(
19324        &mut self,
19325        _: &actions::UnfoldAll,
19326        _window: &mut Window,
19327        cx: &mut Context<Self>,
19328    ) {
19329        if self.buffer.read(cx).is_singleton() {
19330            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19331            self.unfold_ranges(
19332                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19333                true,
19334                true,
19335                cx,
19336            );
19337        } else {
19338            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19339                editor
19340                    .update(cx, |editor, cx| {
19341                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19342                            editor.unfold_buffer(buffer_id, cx);
19343                        }
19344                    })
19345                    .ok();
19346            });
19347        }
19348    }
19349
19350    pub fn fold_selected_ranges(
19351        &mut self,
19352        _: &FoldSelectedRanges,
19353        window: &mut Window,
19354        cx: &mut Context<Self>,
19355    ) {
19356        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19357        let selections = self.selections.all_adjusted(&display_map);
19358        let ranges = selections
19359            .into_iter()
19360            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19361            .collect::<Vec<_>>();
19362        self.fold_creases(ranges, true, window, cx);
19363    }
19364
19365    pub fn fold_ranges<T: ToOffset + Clone>(
19366        &mut self,
19367        ranges: Vec<Range<T>>,
19368        auto_scroll: bool,
19369        window: &mut Window,
19370        cx: &mut Context<Self>,
19371    ) {
19372        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19373        let ranges = ranges
19374            .into_iter()
19375            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19376            .collect::<Vec<_>>();
19377        self.fold_creases(ranges, auto_scroll, window, cx);
19378    }
19379
19380    pub fn fold_creases<T: ToOffset + Clone>(
19381        &mut self,
19382        creases: Vec<Crease<T>>,
19383        auto_scroll: bool,
19384        _window: &mut Window,
19385        cx: &mut Context<Self>,
19386    ) {
19387        if creases.is_empty() {
19388            return;
19389        }
19390
19391        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19392
19393        if auto_scroll {
19394            self.request_autoscroll(Autoscroll::fit(), cx);
19395        }
19396
19397        cx.notify();
19398
19399        self.scrollbar_marker_state.dirty = true;
19400        self.folds_did_change(cx);
19401    }
19402
19403    /// Removes any folds whose ranges intersect any of the given ranges.
19404    pub fn unfold_ranges<T: ToOffset + Clone>(
19405        &mut self,
19406        ranges: &[Range<T>],
19407        inclusive: bool,
19408        auto_scroll: bool,
19409        cx: &mut Context<Self>,
19410    ) {
19411        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19412            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19413        });
19414        self.folds_did_change(cx);
19415    }
19416
19417    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19418        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19419            return;
19420        }
19421
19422        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19423        self.display_map.update(cx, |display_map, cx| {
19424            display_map.fold_buffers([buffer_id], cx)
19425        });
19426
19427        let snapshot = self.display_snapshot(cx);
19428        self.selections.change_with(&snapshot, |selections| {
19429            selections.remove_selections_from_buffer(buffer_id);
19430        });
19431
19432        cx.emit(EditorEvent::BufferFoldToggled {
19433            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19434            folded: true,
19435        });
19436        cx.notify();
19437    }
19438
19439    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19440        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19441            return;
19442        }
19443        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19444        self.display_map.update(cx, |display_map, cx| {
19445            display_map.unfold_buffers([buffer_id], cx);
19446        });
19447        cx.emit(EditorEvent::BufferFoldToggled {
19448            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19449            folded: false,
19450        });
19451        cx.notify();
19452    }
19453
19454    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19455        self.display_map.read(cx).is_buffer_folded(buffer)
19456    }
19457
19458    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19459        self.display_map.read(cx).folded_buffers()
19460    }
19461
19462    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19463        self.display_map.update(cx, |display_map, cx| {
19464            display_map.disable_header_for_buffer(buffer_id, cx);
19465        });
19466        cx.notify();
19467    }
19468
19469    /// Removes any folds with the given ranges.
19470    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19471        &mut self,
19472        ranges: &[Range<T>],
19473        type_id: TypeId,
19474        auto_scroll: bool,
19475        cx: &mut Context<Self>,
19476    ) {
19477        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19478            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19479        });
19480        self.folds_did_change(cx);
19481    }
19482
19483    fn remove_folds_with<T: ToOffset + Clone>(
19484        &mut self,
19485        ranges: &[Range<T>],
19486        auto_scroll: bool,
19487        cx: &mut Context<Self>,
19488        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19489    ) {
19490        if ranges.is_empty() {
19491            return;
19492        }
19493
19494        let mut buffers_affected = HashSet::default();
19495        let multi_buffer = self.buffer().read(cx);
19496        for range in ranges {
19497            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19498                buffers_affected.insert(buffer.read(cx).remote_id());
19499            };
19500        }
19501
19502        self.display_map.update(cx, update);
19503
19504        if auto_scroll {
19505            self.request_autoscroll(Autoscroll::fit(), cx);
19506        }
19507
19508        cx.notify();
19509        self.scrollbar_marker_state.dirty = true;
19510        self.active_indent_guides_state.dirty = true;
19511    }
19512
19513    pub fn update_renderer_widths(
19514        &mut self,
19515        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19516        cx: &mut Context<Self>,
19517    ) -> bool {
19518        self.display_map
19519            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19520    }
19521
19522    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19523        self.display_map.read(cx).fold_placeholder.clone()
19524    }
19525
19526    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19527        self.use_base_text_line_numbers = show;
19528    }
19529
19530    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19531        self.buffer.update(cx, |buffer, cx| {
19532            buffer.set_all_diff_hunks_expanded(cx);
19533        });
19534    }
19535
19536    pub fn expand_all_diff_hunks(
19537        &mut self,
19538        _: &ExpandAllDiffHunks,
19539        _window: &mut Window,
19540        cx: &mut Context<Self>,
19541    ) {
19542        self.buffer.update(cx, |buffer, cx| {
19543            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19544        });
19545    }
19546
19547    pub fn collapse_all_diff_hunks(
19548        &mut self,
19549        _: &CollapseAllDiffHunks,
19550        _window: &mut Window,
19551        cx: &mut Context<Self>,
19552    ) {
19553        self.buffer.update(cx, |buffer, cx| {
19554            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19555        });
19556    }
19557
19558    pub fn toggle_selected_diff_hunks(
19559        &mut self,
19560        _: &ToggleSelectedDiffHunks,
19561        _window: &mut Window,
19562        cx: &mut Context<Self>,
19563    ) {
19564        let ranges: Vec<_> = self
19565            .selections
19566            .disjoint_anchors()
19567            .iter()
19568            .map(|s| s.range())
19569            .collect();
19570        self.toggle_diff_hunks_in_ranges(ranges, cx);
19571    }
19572
19573    pub fn diff_hunks_in_ranges<'a>(
19574        &'a self,
19575        ranges: &'a [Range<Anchor>],
19576        buffer: &'a MultiBufferSnapshot,
19577    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19578        ranges.iter().flat_map(move |range| {
19579            let end_excerpt_id = range.end.excerpt_id;
19580            let range = range.to_point(buffer);
19581            let mut peek_end = range.end;
19582            if range.end.row < buffer.max_row().0 {
19583                peek_end = Point::new(range.end.row + 1, 0);
19584            }
19585            buffer
19586                .diff_hunks_in_range(range.start..peek_end)
19587                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19588        })
19589    }
19590
19591    pub fn has_stageable_diff_hunks_in_ranges(
19592        &self,
19593        ranges: &[Range<Anchor>],
19594        snapshot: &MultiBufferSnapshot,
19595    ) -> bool {
19596        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19597        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19598    }
19599
19600    pub fn toggle_staged_selected_diff_hunks(
19601        &mut self,
19602        _: &::git::ToggleStaged,
19603        _: &mut Window,
19604        cx: &mut Context<Self>,
19605    ) {
19606        let snapshot = self.buffer.read(cx).snapshot(cx);
19607        let ranges: Vec<_> = self
19608            .selections
19609            .disjoint_anchors()
19610            .iter()
19611            .map(|s| s.range())
19612            .collect();
19613        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19614        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19615    }
19616
19617    pub fn set_render_diff_hunk_controls(
19618        &mut self,
19619        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19620        cx: &mut Context<Self>,
19621    ) {
19622        self.render_diff_hunk_controls = render_diff_hunk_controls;
19623        cx.notify();
19624    }
19625
19626    pub fn stage_and_next(
19627        &mut self,
19628        _: &::git::StageAndNext,
19629        window: &mut Window,
19630        cx: &mut Context<Self>,
19631    ) {
19632        self.do_stage_or_unstage_and_next(true, window, cx);
19633    }
19634
19635    pub fn unstage_and_next(
19636        &mut self,
19637        _: &::git::UnstageAndNext,
19638        window: &mut Window,
19639        cx: &mut Context<Self>,
19640    ) {
19641        self.do_stage_or_unstage_and_next(false, window, cx);
19642    }
19643
19644    pub fn stage_or_unstage_diff_hunks(
19645        &mut self,
19646        stage: bool,
19647        ranges: Vec<Range<Anchor>>,
19648        cx: &mut Context<Self>,
19649    ) {
19650        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19651        cx.spawn(async move |this, cx| {
19652            task.await?;
19653            this.update(cx, |this, cx| {
19654                let snapshot = this.buffer.read(cx).snapshot(cx);
19655                let chunk_by = this
19656                    .diff_hunks_in_ranges(&ranges, &snapshot)
19657                    .chunk_by(|hunk| hunk.buffer_id);
19658                for (buffer_id, hunks) in &chunk_by {
19659                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19660                }
19661            })
19662        })
19663        .detach_and_log_err(cx);
19664    }
19665
19666    fn save_buffers_for_ranges_if_needed(
19667        &mut self,
19668        ranges: &[Range<Anchor>],
19669        cx: &mut Context<Editor>,
19670    ) -> Task<Result<()>> {
19671        let multibuffer = self.buffer.read(cx);
19672        let snapshot = multibuffer.read(cx);
19673        let buffer_ids: HashSet<_> = ranges
19674            .iter()
19675            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19676            .collect();
19677        drop(snapshot);
19678
19679        let mut buffers = HashSet::default();
19680        for buffer_id in buffer_ids {
19681            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19682                let buffer = buffer_entity.read(cx);
19683                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19684                {
19685                    buffers.insert(buffer_entity);
19686                }
19687            }
19688        }
19689
19690        if let Some(project) = &self.project {
19691            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19692        } else {
19693            Task::ready(Ok(()))
19694        }
19695    }
19696
19697    fn do_stage_or_unstage_and_next(
19698        &mut self,
19699        stage: bool,
19700        window: &mut Window,
19701        cx: &mut Context<Self>,
19702    ) {
19703        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19704
19705        if ranges.iter().any(|range| range.start != range.end) {
19706            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19707            return;
19708        }
19709
19710        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19711        let snapshot = self.snapshot(window, cx);
19712        let position = self
19713            .selections
19714            .newest::<Point>(&snapshot.display_snapshot)
19715            .head();
19716        let mut row = snapshot
19717            .buffer_snapshot()
19718            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19719            .find(|hunk| hunk.row_range.start.0 > position.row)
19720            .map(|hunk| hunk.row_range.start);
19721
19722        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19723        // Outside of the project diff editor, wrap around to the beginning.
19724        if !all_diff_hunks_expanded {
19725            row = row.or_else(|| {
19726                snapshot
19727                    .buffer_snapshot()
19728                    .diff_hunks_in_range(Point::zero()..position)
19729                    .find(|hunk| hunk.row_range.end.0 < position.row)
19730                    .map(|hunk| hunk.row_range.start)
19731            });
19732        }
19733
19734        if let Some(row) = row {
19735            let destination = Point::new(row.0, 0);
19736            let autoscroll = Autoscroll::center();
19737
19738            self.unfold_ranges(&[destination..destination], false, false, cx);
19739            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19740                s.select_ranges([destination..destination]);
19741            });
19742        }
19743    }
19744
19745    fn do_stage_or_unstage(
19746        &self,
19747        stage: bool,
19748        buffer_id: BufferId,
19749        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19750        cx: &mut App,
19751    ) -> Option<()> {
19752        let project = self.project()?;
19753        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19754        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19755        let buffer_snapshot = buffer.read(cx).snapshot();
19756        let file_exists = buffer_snapshot
19757            .file()
19758            .is_some_and(|file| file.disk_state().exists());
19759        diff.update(cx, |diff, cx| {
19760            diff.stage_or_unstage_hunks(
19761                stage,
19762                &hunks
19763                    .map(|hunk| buffer_diff::DiffHunk {
19764                        buffer_range: hunk.buffer_range,
19765                        // We don't need to pass in word diffs here because they're only used for rendering and
19766                        // this function changes internal state
19767                        base_word_diffs: Vec::default(),
19768                        buffer_word_diffs: Vec::default(),
19769                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19770                            ..hunk.diff_base_byte_range.end.0,
19771                        secondary_status: hunk.secondary_status,
19772                        range: Point::zero()..Point::zero(), // unused
19773                    })
19774                    .collect::<Vec<_>>(),
19775                &buffer_snapshot,
19776                file_exists,
19777                cx,
19778            )
19779        });
19780        None
19781    }
19782
19783    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19784        let ranges: Vec<_> = self
19785            .selections
19786            .disjoint_anchors()
19787            .iter()
19788            .map(|s| s.range())
19789            .collect();
19790        self.buffer
19791            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19792    }
19793
19794    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19795        self.buffer.update(cx, |buffer, cx| {
19796            let ranges = vec![Anchor::min()..Anchor::max()];
19797            if !buffer.all_diff_hunks_expanded()
19798                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19799            {
19800                buffer.collapse_diff_hunks(ranges, cx);
19801                true
19802            } else {
19803                false
19804            }
19805        })
19806    }
19807
19808    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19809        if self.buffer.read(cx).all_diff_hunks_expanded() {
19810            return true;
19811        }
19812        let ranges = vec![Anchor::min()..Anchor::max()];
19813        self.buffer
19814            .read(cx)
19815            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19816    }
19817
19818    fn toggle_diff_hunks_in_ranges(
19819        &mut self,
19820        ranges: Vec<Range<Anchor>>,
19821        cx: &mut Context<Editor>,
19822    ) {
19823        self.buffer.update(cx, |buffer, cx| {
19824            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19825            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19826        })
19827    }
19828
19829    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19830        self.buffer.update(cx, |buffer, cx| {
19831            let snapshot = buffer.snapshot(cx);
19832            let excerpt_id = range.end.excerpt_id;
19833            let point_range = range.to_point(&snapshot);
19834            let expand = !buffer.single_hunk_is_expanded(range, cx);
19835            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19836        })
19837    }
19838
19839    pub(crate) fn apply_all_diff_hunks(
19840        &mut self,
19841        _: &ApplyAllDiffHunks,
19842        window: &mut Window,
19843        cx: &mut Context<Self>,
19844    ) {
19845        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19846
19847        let buffers = self.buffer.read(cx).all_buffers();
19848        for branch_buffer in buffers {
19849            branch_buffer.update(cx, |branch_buffer, cx| {
19850                branch_buffer.merge_into_base(Vec::new(), cx);
19851            });
19852        }
19853
19854        if let Some(project) = self.project.clone() {
19855            self.save(
19856                SaveOptions {
19857                    format: true,
19858                    autosave: false,
19859                },
19860                project,
19861                window,
19862                cx,
19863            )
19864            .detach_and_log_err(cx);
19865        }
19866    }
19867
19868    pub(crate) fn apply_selected_diff_hunks(
19869        &mut self,
19870        _: &ApplyDiffHunk,
19871        window: &mut Window,
19872        cx: &mut Context<Self>,
19873    ) {
19874        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19875        let snapshot = self.snapshot(window, cx);
19876        let hunks = snapshot.hunks_for_ranges(
19877            self.selections
19878                .all(&snapshot.display_snapshot)
19879                .into_iter()
19880                .map(|selection| selection.range()),
19881        );
19882        let mut ranges_by_buffer = HashMap::default();
19883        self.transact(window, cx, |editor, _window, cx| {
19884            for hunk in hunks {
19885                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19886                    ranges_by_buffer
19887                        .entry(buffer.clone())
19888                        .or_insert_with(Vec::new)
19889                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19890                }
19891            }
19892
19893            for (buffer, ranges) in ranges_by_buffer {
19894                buffer.update(cx, |buffer, cx| {
19895                    buffer.merge_into_base(ranges, cx);
19896                });
19897            }
19898        });
19899
19900        if let Some(project) = self.project.clone() {
19901            self.save(
19902                SaveOptions {
19903                    format: true,
19904                    autosave: false,
19905                },
19906                project,
19907                window,
19908                cx,
19909            )
19910            .detach_and_log_err(cx);
19911        }
19912    }
19913
19914    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19915        if hovered != self.gutter_hovered {
19916            self.gutter_hovered = hovered;
19917            cx.notify();
19918        }
19919    }
19920
19921    pub fn insert_blocks(
19922        &mut self,
19923        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19924        autoscroll: Option<Autoscroll>,
19925        cx: &mut Context<Self>,
19926    ) -> Vec<CustomBlockId> {
19927        let blocks = self
19928            .display_map
19929            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19930        if let Some(autoscroll) = autoscroll {
19931            self.request_autoscroll(autoscroll, cx);
19932        }
19933        cx.notify();
19934        blocks
19935    }
19936
19937    pub fn resize_blocks(
19938        &mut self,
19939        heights: HashMap<CustomBlockId, u32>,
19940        autoscroll: Option<Autoscroll>,
19941        cx: &mut Context<Self>,
19942    ) {
19943        self.display_map
19944            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19945        if let Some(autoscroll) = autoscroll {
19946            self.request_autoscroll(autoscroll, cx);
19947        }
19948        cx.notify();
19949    }
19950
19951    pub fn replace_blocks(
19952        &mut self,
19953        renderers: HashMap<CustomBlockId, RenderBlock>,
19954        autoscroll: Option<Autoscroll>,
19955        cx: &mut Context<Self>,
19956    ) {
19957        self.display_map
19958            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19959        if let Some(autoscroll) = autoscroll {
19960            self.request_autoscroll(autoscroll, cx);
19961        }
19962        cx.notify();
19963    }
19964
19965    pub fn remove_blocks(
19966        &mut self,
19967        block_ids: HashSet<CustomBlockId>,
19968        autoscroll: Option<Autoscroll>,
19969        cx: &mut Context<Self>,
19970    ) {
19971        self.display_map.update(cx, |display_map, cx| {
19972            display_map.remove_blocks(block_ids, cx)
19973        });
19974        if let Some(autoscroll) = autoscroll {
19975            self.request_autoscroll(autoscroll, cx);
19976        }
19977        cx.notify();
19978    }
19979
19980    pub fn row_for_block(
19981        &self,
19982        block_id: CustomBlockId,
19983        cx: &mut Context<Self>,
19984    ) -> Option<DisplayRow> {
19985        self.display_map
19986            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19987    }
19988
19989    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19990        self.focused_block = Some(focused_block);
19991    }
19992
19993    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19994        self.focused_block.take()
19995    }
19996
19997    pub fn insert_creases(
19998        &mut self,
19999        creases: impl IntoIterator<Item = Crease<Anchor>>,
20000        cx: &mut Context<Self>,
20001    ) -> Vec<CreaseId> {
20002        self.display_map
20003            .update(cx, |map, cx| map.insert_creases(creases, cx))
20004    }
20005
20006    pub fn remove_creases(
20007        &mut self,
20008        ids: impl IntoIterator<Item = CreaseId>,
20009        cx: &mut Context<Self>,
20010    ) -> Vec<(CreaseId, Range<Anchor>)> {
20011        self.display_map
20012            .update(cx, |map, cx| map.remove_creases(ids, cx))
20013    }
20014
20015    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20016        self.display_map
20017            .update(cx, |map, cx| map.snapshot(cx))
20018            .longest_row()
20019    }
20020
20021    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20022        self.display_map
20023            .update(cx, |map, cx| map.snapshot(cx))
20024            .max_point()
20025    }
20026
20027    pub fn text(&self, cx: &App) -> String {
20028        self.buffer.read(cx).read(cx).text()
20029    }
20030
20031    pub fn is_empty(&self, cx: &App) -> bool {
20032        self.buffer.read(cx).read(cx).is_empty()
20033    }
20034
20035    pub fn text_option(&self, cx: &App) -> Option<String> {
20036        let text = self.text(cx);
20037        let text = text.trim();
20038
20039        if text.is_empty() {
20040            return None;
20041        }
20042
20043        Some(text.to_string())
20044    }
20045
20046    pub fn set_text(
20047        &mut self,
20048        text: impl Into<Arc<str>>,
20049        window: &mut Window,
20050        cx: &mut Context<Self>,
20051    ) {
20052        self.transact(window, cx, |this, _, cx| {
20053            this.buffer
20054                .read(cx)
20055                .as_singleton()
20056                .expect("you can only call set_text on editors for singleton buffers")
20057                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20058        });
20059    }
20060
20061    pub fn display_text(&self, cx: &mut App) -> String {
20062        self.display_map
20063            .update(cx, |map, cx| map.snapshot(cx))
20064            .text()
20065    }
20066
20067    fn create_minimap(
20068        &self,
20069        minimap_settings: MinimapSettings,
20070        window: &mut Window,
20071        cx: &mut Context<Self>,
20072    ) -> Option<Entity<Self>> {
20073        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20074            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20075    }
20076
20077    fn initialize_new_minimap(
20078        &self,
20079        minimap_settings: MinimapSettings,
20080        window: &mut Window,
20081        cx: &mut Context<Self>,
20082    ) -> Entity<Self> {
20083        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20084
20085        let mut minimap = Editor::new_internal(
20086            EditorMode::Minimap {
20087                parent: cx.weak_entity(),
20088            },
20089            self.buffer.clone(),
20090            None,
20091            Some(self.display_map.clone()),
20092            window,
20093            cx,
20094        );
20095        minimap.scroll_manager.clone_state(&self.scroll_manager);
20096        minimap.set_text_style_refinement(TextStyleRefinement {
20097            font_size: Some(MINIMAP_FONT_SIZE),
20098            font_weight: Some(MINIMAP_FONT_WEIGHT),
20099            ..Default::default()
20100        });
20101        minimap.update_minimap_configuration(minimap_settings, cx);
20102        cx.new(|_| minimap)
20103    }
20104
20105    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20106        let current_line_highlight = minimap_settings
20107            .current_line_highlight
20108            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20109        self.set_current_line_highlight(Some(current_line_highlight));
20110    }
20111
20112    pub fn minimap(&self) -> Option<&Entity<Self>> {
20113        self.minimap
20114            .as_ref()
20115            .filter(|_| self.minimap_visibility.visible())
20116    }
20117
20118    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20119        let mut wrap_guides = smallvec![];
20120
20121        if self.show_wrap_guides == Some(false) {
20122            return wrap_guides;
20123        }
20124
20125        let settings = self.buffer.read(cx).language_settings(cx);
20126        if settings.show_wrap_guides {
20127            match self.soft_wrap_mode(cx) {
20128                SoftWrap::Column(soft_wrap) => {
20129                    wrap_guides.push((soft_wrap as usize, true));
20130                }
20131                SoftWrap::Bounded(soft_wrap) => {
20132                    wrap_guides.push((soft_wrap as usize, true));
20133                }
20134                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20135            }
20136            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20137        }
20138
20139        wrap_guides
20140    }
20141
20142    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20143        let settings = self.buffer.read(cx).language_settings(cx);
20144        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20145        match mode {
20146            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20147                SoftWrap::None
20148            }
20149            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20150            language_settings::SoftWrap::PreferredLineLength => {
20151                SoftWrap::Column(settings.preferred_line_length)
20152            }
20153            language_settings::SoftWrap::Bounded => {
20154                SoftWrap::Bounded(settings.preferred_line_length)
20155            }
20156        }
20157    }
20158
20159    pub fn set_soft_wrap_mode(
20160        &mut self,
20161        mode: language_settings::SoftWrap,
20162
20163        cx: &mut Context<Self>,
20164    ) {
20165        self.soft_wrap_mode_override = Some(mode);
20166        cx.notify();
20167    }
20168
20169    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20170        self.hard_wrap = hard_wrap;
20171        cx.notify();
20172    }
20173
20174    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20175        self.text_style_refinement = Some(style);
20176    }
20177
20178    /// called by the Element so we know what style we were most recently rendered with.
20179    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20180        // We intentionally do not inform the display map about the minimap style
20181        // so that wrapping is not recalculated and stays consistent for the editor
20182        // and its linked minimap.
20183        if !self.mode.is_minimap() {
20184            let font = style.text.font();
20185            let font_size = style.text.font_size.to_pixels(window.rem_size());
20186            let display_map = self
20187                .placeholder_display_map
20188                .as_ref()
20189                .filter(|_| self.is_empty(cx))
20190                .unwrap_or(&self.display_map);
20191
20192            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20193        }
20194        self.style = Some(style);
20195    }
20196
20197    pub fn style(&self) -> Option<&EditorStyle> {
20198        self.style.as_ref()
20199    }
20200
20201    // Called by the element. This method is not designed to be called outside of the editor
20202    // element's layout code because it does not notify when rewrapping is computed synchronously.
20203    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20204        if self.is_empty(cx) {
20205            self.placeholder_display_map
20206                .as_ref()
20207                .map_or(false, |display_map| {
20208                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20209                })
20210        } else {
20211            self.display_map
20212                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20213        }
20214    }
20215
20216    pub fn set_soft_wrap(&mut self) {
20217        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20218    }
20219
20220    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20221        if self.soft_wrap_mode_override.is_some() {
20222            self.soft_wrap_mode_override.take();
20223        } else {
20224            let soft_wrap = match self.soft_wrap_mode(cx) {
20225                SoftWrap::GitDiff => return,
20226                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20227                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20228                    language_settings::SoftWrap::None
20229                }
20230            };
20231            self.soft_wrap_mode_override = Some(soft_wrap);
20232        }
20233        cx.notify();
20234    }
20235
20236    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20237        let Some(workspace) = self.workspace() else {
20238            return;
20239        };
20240        let fs = workspace.read(cx).app_state().fs.clone();
20241        let current_show = TabBarSettings::get_global(cx).show;
20242        update_settings_file(fs, cx, move |setting, _| {
20243            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20244        });
20245    }
20246
20247    pub fn toggle_indent_guides(
20248        &mut self,
20249        _: &ToggleIndentGuides,
20250        _: &mut Window,
20251        cx: &mut Context<Self>,
20252    ) {
20253        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20254            self.buffer
20255                .read(cx)
20256                .language_settings(cx)
20257                .indent_guides
20258                .enabled
20259        });
20260        self.show_indent_guides = Some(!currently_enabled);
20261        cx.notify();
20262    }
20263
20264    fn should_show_indent_guides(&self) -> Option<bool> {
20265        self.show_indent_guides
20266    }
20267
20268    pub fn disable_indent_guides_for_buffer(
20269        &mut self,
20270        buffer_id: BufferId,
20271        cx: &mut Context<Self>,
20272    ) {
20273        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20274        cx.notify();
20275    }
20276
20277    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20278        self.buffers_with_disabled_indent_guides
20279            .contains(&buffer_id)
20280    }
20281
20282    pub fn toggle_line_numbers(
20283        &mut self,
20284        _: &ToggleLineNumbers,
20285        _: &mut Window,
20286        cx: &mut Context<Self>,
20287    ) {
20288        let mut editor_settings = EditorSettings::get_global(cx).clone();
20289        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20290        EditorSettings::override_global(editor_settings, cx);
20291    }
20292
20293    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20294        if let Some(show_line_numbers) = self.show_line_numbers {
20295            return show_line_numbers;
20296        }
20297        EditorSettings::get_global(cx).gutter.line_numbers
20298    }
20299
20300    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20301        match (
20302            self.use_relative_line_numbers,
20303            EditorSettings::get_global(cx).relative_line_numbers,
20304        ) {
20305            (None, setting) => setting,
20306            (Some(false), _) => RelativeLineNumbers::Disabled,
20307            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20308            (Some(true), _) => RelativeLineNumbers::Enabled,
20309        }
20310    }
20311
20312    pub fn toggle_relative_line_numbers(
20313        &mut self,
20314        _: &ToggleRelativeLineNumbers,
20315        _: &mut Window,
20316        cx: &mut Context<Self>,
20317    ) {
20318        let is_relative = self.relative_line_numbers(cx);
20319        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20320    }
20321
20322    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20323        self.use_relative_line_numbers = is_relative;
20324        cx.notify();
20325    }
20326
20327    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20328        self.show_gutter = show_gutter;
20329        cx.notify();
20330    }
20331
20332    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20333        self.show_scrollbars = ScrollbarAxes {
20334            horizontal: show,
20335            vertical: show,
20336        };
20337        cx.notify();
20338    }
20339
20340    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20341        self.show_scrollbars.vertical = show;
20342        cx.notify();
20343    }
20344
20345    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20346        self.show_scrollbars.horizontal = show;
20347        cx.notify();
20348    }
20349
20350    pub fn set_minimap_visibility(
20351        &mut self,
20352        minimap_visibility: MinimapVisibility,
20353        window: &mut Window,
20354        cx: &mut Context<Self>,
20355    ) {
20356        if self.minimap_visibility != minimap_visibility {
20357            if minimap_visibility.visible() && self.minimap.is_none() {
20358                let minimap_settings = EditorSettings::get_global(cx).minimap;
20359                self.minimap =
20360                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20361            }
20362            self.minimap_visibility = minimap_visibility;
20363            cx.notify();
20364        }
20365    }
20366
20367    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20368        self.set_show_scrollbars(false, cx);
20369        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20370    }
20371
20372    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20373        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20374    }
20375
20376    /// Normally the text in full mode and auto height editors is padded on the
20377    /// left side by roughly half a character width for improved hit testing.
20378    ///
20379    /// Use this method to disable this for cases where this is not wanted (e.g.
20380    /// if you want to align the editor text with some other text above or below)
20381    /// or if you want to add this padding to single-line editors.
20382    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20383        self.offset_content = offset_content;
20384        cx.notify();
20385    }
20386
20387    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20388        self.show_line_numbers = Some(show_line_numbers);
20389        cx.notify();
20390    }
20391
20392    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20393        self.disable_expand_excerpt_buttons = true;
20394        cx.notify();
20395    }
20396
20397    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20398        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20399        cx.notify();
20400    }
20401
20402    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20403        self.show_code_actions = Some(show_code_actions);
20404        cx.notify();
20405    }
20406
20407    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20408        self.show_runnables = Some(show_runnables);
20409        cx.notify();
20410    }
20411
20412    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20413        self.show_breakpoints = Some(show_breakpoints);
20414        cx.notify();
20415    }
20416
20417    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20418        if self.display_map.read(cx).masked != masked {
20419            self.display_map.update(cx, |map, _| map.masked = masked);
20420        }
20421        cx.notify()
20422    }
20423
20424    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20425        self.show_wrap_guides = Some(show_wrap_guides);
20426        cx.notify();
20427    }
20428
20429    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20430        self.show_indent_guides = Some(show_indent_guides);
20431        cx.notify();
20432    }
20433
20434    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20435        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20436            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20437                && let Some(dir) = file.abs_path(cx).parent()
20438            {
20439                return Some(dir.to_owned());
20440            }
20441        }
20442
20443        None
20444    }
20445
20446    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20447        self.active_excerpt(cx)?
20448            .1
20449            .read(cx)
20450            .file()
20451            .and_then(|f| f.as_local())
20452    }
20453
20454    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20455        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20456            let buffer = buffer.read(cx);
20457            if let Some(project_path) = buffer.project_path(cx) {
20458                let project = self.project()?.read(cx);
20459                project.absolute_path(&project_path, cx)
20460            } else {
20461                buffer
20462                    .file()
20463                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20464            }
20465        })
20466    }
20467
20468    pub fn reveal_in_finder(
20469        &mut self,
20470        _: &RevealInFileManager,
20471        _window: &mut Window,
20472        cx: &mut Context<Self>,
20473    ) {
20474        if let Some(target) = self.target_file(cx) {
20475            cx.reveal_path(&target.abs_path(cx));
20476        }
20477    }
20478
20479    pub fn copy_path(
20480        &mut self,
20481        _: &zed_actions::workspace::CopyPath,
20482        _window: &mut Window,
20483        cx: &mut Context<Self>,
20484    ) {
20485        if let Some(path) = self.target_file_abs_path(cx)
20486            && let Some(path) = path.to_str()
20487        {
20488            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20489        } else {
20490            cx.propagate();
20491        }
20492    }
20493
20494    pub fn copy_relative_path(
20495        &mut self,
20496        _: &zed_actions::workspace::CopyRelativePath,
20497        _window: &mut Window,
20498        cx: &mut Context<Self>,
20499    ) {
20500        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20501            let project = self.project()?.read(cx);
20502            let path = buffer.read(cx).file()?.path();
20503            let path = path.display(project.path_style(cx));
20504            Some(path)
20505        }) {
20506            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20507        } else {
20508            cx.propagate();
20509        }
20510    }
20511
20512    /// Returns the project path for the editor's buffer, if any buffer is
20513    /// opened in the editor.
20514    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20515        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20516            buffer.read(cx).project_path(cx)
20517        } else {
20518            None
20519        }
20520    }
20521
20522    // Returns true if the editor handled a go-to-line request
20523    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20524        maybe!({
20525            let breakpoint_store = self.breakpoint_store.as_ref()?;
20526
20527            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20528            else {
20529                self.clear_row_highlights::<ActiveDebugLine>();
20530                return None;
20531            };
20532
20533            let position = active_stack_frame.position;
20534            let buffer_id = position.buffer_id?;
20535            let snapshot = self
20536                .project
20537                .as_ref()?
20538                .read(cx)
20539                .buffer_for_id(buffer_id, cx)?
20540                .read(cx)
20541                .snapshot();
20542
20543            let mut handled = false;
20544            for (id, ExcerptRange { context, .. }) in
20545                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20546            {
20547                if context.start.cmp(&position, &snapshot).is_ge()
20548                    || context.end.cmp(&position, &snapshot).is_lt()
20549                {
20550                    continue;
20551                }
20552                let snapshot = self.buffer.read(cx).snapshot(cx);
20553                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20554
20555                handled = true;
20556                self.clear_row_highlights::<ActiveDebugLine>();
20557
20558                self.go_to_line::<ActiveDebugLine>(
20559                    multibuffer_anchor,
20560                    Some(cx.theme().colors().editor_debugger_active_line_background),
20561                    window,
20562                    cx,
20563                );
20564
20565                cx.notify();
20566            }
20567
20568            handled.then_some(())
20569        })
20570        .is_some()
20571    }
20572
20573    pub fn copy_file_name_without_extension(
20574        &mut self,
20575        _: &CopyFileNameWithoutExtension,
20576        _: &mut Window,
20577        cx: &mut Context<Self>,
20578    ) {
20579        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20580            let file = buffer.read(cx).file()?;
20581            file.path().file_stem()
20582        }) {
20583            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20584        }
20585    }
20586
20587    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20588        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20589            let file = buffer.read(cx).file()?;
20590            Some(file.file_name(cx))
20591        }) {
20592            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20593        }
20594    }
20595
20596    pub fn toggle_git_blame(
20597        &mut self,
20598        _: &::git::Blame,
20599        window: &mut Window,
20600        cx: &mut Context<Self>,
20601    ) {
20602        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20603
20604        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20605            self.start_git_blame(true, window, cx);
20606        }
20607
20608        cx.notify();
20609    }
20610
20611    pub fn toggle_git_blame_inline(
20612        &mut self,
20613        _: &ToggleGitBlameInline,
20614        window: &mut Window,
20615        cx: &mut Context<Self>,
20616    ) {
20617        self.toggle_git_blame_inline_internal(true, window, cx);
20618        cx.notify();
20619    }
20620
20621    pub fn open_git_blame_commit(
20622        &mut self,
20623        _: &OpenGitBlameCommit,
20624        window: &mut Window,
20625        cx: &mut Context<Self>,
20626    ) {
20627        self.open_git_blame_commit_internal(window, cx);
20628    }
20629
20630    fn open_git_blame_commit_internal(
20631        &mut self,
20632        window: &mut Window,
20633        cx: &mut Context<Self>,
20634    ) -> Option<()> {
20635        let blame = self.blame.as_ref()?;
20636        let snapshot = self.snapshot(window, cx);
20637        let cursor = self
20638            .selections
20639            .newest::<Point>(&snapshot.display_snapshot)
20640            .head();
20641        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20642        let (_, blame_entry) = blame
20643            .update(cx, |blame, cx| {
20644                blame
20645                    .blame_for_rows(
20646                        &[RowInfo {
20647                            buffer_id: Some(buffer.remote_id()),
20648                            buffer_row: Some(point.row),
20649                            ..Default::default()
20650                        }],
20651                        cx,
20652                    )
20653                    .next()
20654            })
20655            .flatten()?;
20656        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20657        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20658        let workspace = self.workspace()?.downgrade();
20659        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20660        None
20661    }
20662
20663    pub fn git_blame_inline_enabled(&self) -> bool {
20664        self.git_blame_inline_enabled
20665    }
20666
20667    pub fn toggle_selection_menu(
20668        &mut self,
20669        _: &ToggleSelectionMenu,
20670        _: &mut Window,
20671        cx: &mut Context<Self>,
20672    ) {
20673        self.show_selection_menu = self
20674            .show_selection_menu
20675            .map(|show_selections_menu| !show_selections_menu)
20676            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20677
20678        cx.notify();
20679    }
20680
20681    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20682        self.show_selection_menu
20683            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20684    }
20685
20686    fn start_git_blame(
20687        &mut self,
20688        user_triggered: bool,
20689        window: &mut Window,
20690        cx: &mut Context<Self>,
20691    ) {
20692        if let Some(project) = self.project() {
20693            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20694                && buffer.read(cx).file().is_none()
20695            {
20696                return;
20697            }
20698
20699            let focused = self.focus_handle(cx).contains_focused(window, cx);
20700
20701            let project = project.clone();
20702            let blame = cx
20703                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20704            self.blame_subscription =
20705                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20706            self.blame = Some(blame);
20707        }
20708    }
20709
20710    fn toggle_git_blame_inline_internal(
20711        &mut self,
20712        user_triggered: bool,
20713        window: &mut Window,
20714        cx: &mut Context<Self>,
20715    ) {
20716        if self.git_blame_inline_enabled {
20717            self.git_blame_inline_enabled = false;
20718            self.show_git_blame_inline = false;
20719            self.show_git_blame_inline_delay_task.take();
20720        } else {
20721            self.git_blame_inline_enabled = true;
20722            self.start_git_blame_inline(user_triggered, window, cx);
20723        }
20724
20725        cx.notify();
20726    }
20727
20728    fn start_git_blame_inline(
20729        &mut self,
20730        user_triggered: bool,
20731        window: &mut Window,
20732        cx: &mut Context<Self>,
20733    ) {
20734        self.start_git_blame(user_triggered, window, cx);
20735
20736        if ProjectSettings::get_global(cx)
20737            .git
20738            .inline_blame_delay()
20739            .is_some()
20740        {
20741            self.start_inline_blame_timer(window, cx);
20742        } else {
20743            self.show_git_blame_inline = true
20744        }
20745    }
20746
20747    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20748        self.blame.as_ref()
20749    }
20750
20751    pub fn show_git_blame_gutter(&self) -> bool {
20752        self.show_git_blame_gutter
20753    }
20754
20755    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20756        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20757    }
20758
20759    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20760        self.show_git_blame_inline
20761            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20762            && !self.newest_selection_head_on_empty_line(cx)
20763            && self.has_blame_entries(cx)
20764    }
20765
20766    fn has_blame_entries(&self, cx: &App) -> bool {
20767        self.blame()
20768            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20769    }
20770
20771    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20772        let cursor_anchor = self.selections.newest_anchor().head();
20773
20774        let snapshot = self.buffer.read(cx).snapshot(cx);
20775        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20776
20777        snapshot.line_len(buffer_row) == 0
20778    }
20779
20780    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20781        let buffer_and_selection = maybe!({
20782            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20783            let selection_range = selection.range();
20784
20785            let multi_buffer = self.buffer().read(cx);
20786            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20787            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20788
20789            let (buffer, range, _) = if selection.reversed {
20790                buffer_ranges.first()
20791            } else {
20792                buffer_ranges.last()
20793            }?;
20794
20795            let selection = text::ToPoint::to_point(&range.start, buffer).row
20796                ..text::ToPoint::to_point(&range.end, buffer).row;
20797            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20798        });
20799
20800        let Some((buffer, selection)) = buffer_and_selection else {
20801            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20802        };
20803
20804        let Some(project) = self.project() else {
20805            return Task::ready(Err(anyhow!("editor does not have project")));
20806        };
20807
20808        project.update(cx, |project, cx| {
20809            project.get_permalink_to_line(&buffer, selection, cx)
20810        })
20811    }
20812
20813    pub fn copy_permalink_to_line(
20814        &mut self,
20815        _: &CopyPermalinkToLine,
20816        window: &mut Window,
20817        cx: &mut Context<Self>,
20818    ) {
20819        let permalink_task = self.get_permalink_to_line(cx);
20820        let workspace = self.workspace();
20821
20822        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20823            Ok(permalink) => {
20824                cx.update(|_, cx| {
20825                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20826                })
20827                .ok();
20828            }
20829            Err(err) => {
20830                let message = format!("Failed to copy permalink: {err}");
20831
20832                anyhow::Result::<()>::Err(err).log_err();
20833
20834                if let Some(workspace) = workspace {
20835                    workspace
20836                        .update_in(cx, |workspace, _, cx| {
20837                            struct CopyPermalinkToLine;
20838
20839                            workspace.show_toast(
20840                                Toast::new(
20841                                    NotificationId::unique::<CopyPermalinkToLine>(),
20842                                    message,
20843                                ),
20844                                cx,
20845                            )
20846                        })
20847                        .ok();
20848                }
20849            }
20850        })
20851        .detach();
20852    }
20853
20854    pub fn copy_file_location(
20855        &mut self,
20856        _: &CopyFileLocation,
20857        _: &mut Window,
20858        cx: &mut Context<Self>,
20859    ) {
20860        let selection = self
20861            .selections
20862            .newest::<Point>(&self.display_snapshot(cx))
20863            .start
20864            .row
20865            + 1;
20866        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20867            let project = self.project()?.read(cx);
20868            let file = buffer.read(cx).file()?;
20869            let path = file.path().display(project.path_style(cx));
20870
20871            Some(format!("{path}:{selection}"))
20872        }) {
20873            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
20874        }
20875    }
20876
20877    pub fn open_permalink_to_line(
20878        &mut self,
20879        _: &OpenPermalinkToLine,
20880        window: &mut Window,
20881        cx: &mut Context<Self>,
20882    ) {
20883        let permalink_task = self.get_permalink_to_line(cx);
20884        let workspace = self.workspace();
20885
20886        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20887            Ok(permalink) => {
20888                cx.update(|_, cx| {
20889                    cx.open_url(permalink.as_ref());
20890                })
20891                .ok();
20892            }
20893            Err(err) => {
20894                let message = format!("Failed to open permalink: {err}");
20895
20896                anyhow::Result::<()>::Err(err).log_err();
20897
20898                if let Some(workspace) = workspace {
20899                    workspace
20900                        .update(cx, |workspace, cx| {
20901                            struct OpenPermalinkToLine;
20902
20903                            workspace.show_toast(
20904                                Toast::new(
20905                                    NotificationId::unique::<OpenPermalinkToLine>(),
20906                                    message,
20907                                ),
20908                                cx,
20909                            )
20910                        })
20911                        .ok();
20912                }
20913            }
20914        })
20915        .detach();
20916    }
20917
20918    pub fn insert_uuid_v4(
20919        &mut self,
20920        _: &InsertUuidV4,
20921        window: &mut Window,
20922        cx: &mut Context<Self>,
20923    ) {
20924        self.insert_uuid(UuidVersion::V4, window, cx);
20925    }
20926
20927    pub fn insert_uuid_v7(
20928        &mut self,
20929        _: &InsertUuidV7,
20930        window: &mut Window,
20931        cx: &mut Context<Self>,
20932    ) {
20933        self.insert_uuid(UuidVersion::V7, window, cx);
20934    }
20935
20936    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20937        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20938        self.transact(window, cx, |this, window, cx| {
20939            let edits = this
20940                .selections
20941                .all::<Point>(&this.display_snapshot(cx))
20942                .into_iter()
20943                .map(|selection| {
20944                    let uuid = match version {
20945                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20946                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20947                    };
20948
20949                    (selection.range(), uuid.to_string())
20950                });
20951            this.edit(edits, cx);
20952            this.refresh_edit_prediction(true, false, window, cx);
20953        });
20954    }
20955
20956    pub fn open_selections_in_multibuffer(
20957        &mut self,
20958        _: &OpenSelectionsInMultibuffer,
20959        window: &mut Window,
20960        cx: &mut Context<Self>,
20961    ) {
20962        let multibuffer = self.buffer.read(cx);
20963
20964        let Some(buffer) = multibuffer.as_singleton() else {
20965            return;
20966        };
20967
20968        let Some(workspace) = self.workspace() else {
20969            return;
20970        };
20971
20972        let title = multibuffer.title(cx).to_string();
20973
20974        let locations = self
20975            .selections
20976            .all_anchors(&self.display_snapshot(cx))
20977            .iter()
20978            .map(|selection| {
20979                (
20980                    buffer.clone(),
20981                    (selection.start.text_anchor..selection.end.text_anchor)
20982                        .to_point(buffer.read(cx)),
20983                )
20984            })
20985            .into_group_map();
20986
20987        cx.spawn_in(window, async move |_, cx| {
20988            workspace.update_in(cx, |workspace, window, cx| {
20989                Self::open_locations_in_multibuffer(
20990                    workspace,
20991                    locations,
20992                    format!("Selections for '{title}'"),
20993                    false,
20994                    false,
20995                    MultibufferSelectionMode::All,
20996                    window,
20997                    cx,
20998                );
20999            })
21000        })
21001        .detach();
21002    }
21003
21004    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21005    /// last highlight added will be used.
21006    ///
21007    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21008    pub fn highlight_rows<T: 'static>(
21009        &mut self,
21010        range: Range<Anchor>,
21011        color: Hsla,
21012        options: RowHighlightOptions,
21013        cx: &mut Context<Self>,
21014    ) {
21015        let snapshot = self.buffer().read(cx).snapshot(cx);
21016        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21017        let ix = row_highlights.binary_search_by(|highlight| {
21018            Ordering::Equal
21019                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21020                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21021        });
21022
21023        if let Err(mut ix) = ix {
21024            let index = post_inc(&mut self.highlight_order);
21025
21026            // If this range intersects with the preceding highlight, then merge it with
21027            // the preceding highlight. Otherwise insert a new highlight.
21028            let mut merged = false;
21029            if ix > 0 {
21030                let prev_highlight = &mut row_highlights[ix - 1];
21031                if prev_highlight
21032                    .range
21033                    .end
21034                    .cmp(&range.start, &snapshot)
21035                    .is_ge()
21036                {
21037                    ix -= 1;
21038                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21039                        prev_highlight.range.end = range.end;
21040                    }
21041                    merged = true;
21042                    prev_highlight.index = index;
21043                    prev_highlight.color = color;
21044                    prev_highlight.options = options;
21045                }
21046            }
21047
21048            if !merged {
21049                row_highlights.insert(
21050                    ix,
21051                    RowHighlight {
21052                        range,
21053                        index,
21054                        color,
21055                        options,
21056                        type_id: TypeId::of::<T>(),
21057                    },
21058                );
21059            }
21060
21061            // If any of the following highlights intersect with this one, merge them.
21062            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21063                let highlight = &row_highlights[ix];
21064                if next_highlight
21065                    .range
21066                    .start
21067                    .cmp(&highlight.range.end, &snapshot)
21068                    .is_le()
21069                {
21070                    if next_highlight
21071                        .range
21072                        .end
21073                        .cmp(&highlight.range.end, &snapshot)
21074                        .is_gt()
21075                    {
21076                        row_highlights[ix].range.end = next_highlight.range.end;
21077                    }
21078                    row_highlights.remove(ix + 1);
21079                } else {
21080                    break;
21081                }
21082            }
21083        }
21084    }
21085
21086    /// Remove any highlighted row ranges of the given type that intersect the
21087    /// given ranges.
21088    pub fn remove_highlighted_rows<T: 'static>(
21089        &mut self,
21090        ranges_to_remove: Vec<Range<Anchor>>,
21091        cx: &mut Context<Self>,
21092    ) {
21093        let snapshot = self.buffer().read(cx).snapshot(cx);
21094        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21095        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21096        row_highlights.retain(|highlight| {
21097            while let Some(range_to_remove) = ranges_to_remove.peek() {
21098                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21099                    Ordering::Less | Ordering::Equal => {
21100                        ranges_to_remove.next();
21101                    }
21102                    Ordering::Greater => {
21103                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21104                            Ordering::Less | Ordering::Equal => {
21105                                return false;
21106                            }
21107                            Ordering::Greater => break,
21108                        }
21109                    }
21110                }
21111            }
21112
21113            true
21114        })
21115    }
21116
21117    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21118    pub fn clear_row_highlights<T: 'static>(&mut self) {
21119        self.highlighted_rows.remove(&TypeId::of::<T>());
21120    }
21121
21122    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21123    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21124        self.highlighted_rows
21125            .get(&TypeId::of::<T>())
21126            .map_or(&[] as &[_], |vec| vec.as_slice())
21127            .iter()
21128            .map(|highlight| (highlight.range.clone(), highlight.color))
21129    }
21130
21131    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21132    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21133    /// Allows to ignore certain kinds of highlights.
21134    pub fn highlighted_display_rows(
21135        &self,
21136        window: &mut Window,
21137        cx: &mut App,
21138    ) -> BTreeMap<DisplayRow, LineHighlight> {
21139        let snapshot = self.snapshot(window, cx);
21140        let mut used_highlight_orders = HashMap::default();
21141        self.highlighted_rows
21142            .iter()
21143            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21144            .fold(
21145                BTreeMap::<DisplayRow, LineHighlight>::new(),
21146                |mut unique_rows, highlight| {
21147                    let start = highlight.range.start.to_display_point(&snapshot);
21148                    let end = highlight.range.end.to_display_point(&snapshot);
21149                    let start_row = start.row().0;
21150                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21151                    {
21152                        end.row().0.saturating_sub(1)
21153                    } else {
21154                        end.row().0
21155                    };
21156                    for row in start_row..=end_row {
21157                        let used_index =
21158                            used_highlight_orders.entry(row).or_insert(highlight.index);
21159                        if highlight.index >= *used_index {
21160                            *used_index = highlight.index;
21161                            unique_rows.insert(
21162                                DisplayRow(row),
21163                                LineHighlight {
21164                                    include_gutter: highlight.options.include_gutter,
21165                                    border: None,
21166                                    background: highlight.color.into(),
21167                                    type_id: Some(highlight.type_id),
21168                                },
21169                            );
21170                        }
21171                    }
21172                    unique_rows
21173                },
21174            )
21175    }
21176
21177    pub fn highlighted_display_row_for_autoscroll(
21178        &self,
21179        snapshot: &DisplaySnapshot,
21180    ) -> Option<DisplayRow> {
21181        self.highlighted_rows
21182            .values()
21183            .flat_map(|highlighted_rows| highlighted_rows.iter())
21184            .filter_map(|highlight| {
21185                if highlight.options.autoscroll {
21186                    Some(highlight.range.start.to_display_point(snapshot).row())
21187                } else {
21188                    None
21189                }
21190            })
21191            .min()
21192    }
21193
21194    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21195        self.highlight_background::<SearchWithinRange>(
21196            ranges,
21197            |_, colors| colors.colors().editor_document_highlight_read_background,
21198            cx,
21199        )
21200    }
21201
21202    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21203        self.breadcrumb_header = Some(new_header);
21204    }
21205
21206    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21207        self.clear_background_highlights::<SearchWithinRange>(cx);
21208    }
21209
21210    pub fn highlight_background<T: 'static>(
21211        &mut self,
21212        ranges: &[Range<Anchor>],
21213        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21214        cx: &mut Context<Self>,
21215    ) {
21216        self.background_highlights.insert(
21217            HighlightKey::Type(TypeId::of::<T>()),
21218            (Arc::new(color_fetcher), Arc::from(ranges)),
21219        );
21220        self.scrollbar_marker_state.dirty = true;
21221        cx.notify();
21222    }
21223
21224    pub fn highlight_background_key<T: 'static>(
21225        &mut self,
21226        key: usize,
21227        ranges: &[Range<Anchor>],
21228        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21229        cx: &mut Context<Self>,
21230    ) {
21231        self.background_highlights.insert(
21232            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21233            (Arc::new(color_fetcher), Arc::from(ranges)),
21234        );
21235        self.scrollbar_marker_state.dirty = true;
21236        cx.notify();
21237    }
21238
21239    pub fn clear_background_highlights<T: 'static>(
21240        &mut self,
21241        cx: &mut Context<Self>,
21242    ) -> Option<BackgroundHighlight> {
21243        let text_highlights = self
21244            .background_highlights
21245            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21246        if !text_highlights.1.is_empty() {
21247            self.scrollbar_marker_state.dirty = true;
21248            cx.notify();
21249        }
21250        Some(text_highlights)
21251    }
21252
21253    pub fn highlight_gutter<T: 'static>(
21254        &mut self,
21255        ranges: impl Into<Vec<Range<Anchor>>>,
21256        color_fetcher: fn(&App) -> Hsla,
21257        cx: &mut Context<Self>,
21258    ) {
21259        self.gutter_highlights
21260            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21261        cx.notify();
21262    }
21263
21264    pub fn clear_gutter_highlights<T: 'static>(
21265        &mut self,
21266        cx: &mut Context<Self>,
21267    ) -> Option<GutterHighlight> {
21268        cx.notify();
21269        self.gutter_highlights.remove(&TypeId::of::<T>())
21270    }
21271
21272    pub fn insert_gutter_highlight<T: 'static>(
21273        &mut self,
21274        range: Range<Anchor>,
21275        color_fetcher: fn(&App) -> Hsla,
21276        cx: &mut Context<Self>,
21277    ) {
21278        let snapshot = self.buffer().read(cx).snapshot(cx);
21279        let mut highlights = self
21280            .gutter_highlights
21281            .remove(&TypeId::of::<T>())
21282            .map(|(_, highlights)| highlights)
21283            .unwrap_or_default();
21284        let ix = highlights.binary_search_by(|highlight| {
21285            Ordering::Equal
21286                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21287                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21288        });
21289        if let Err(ix) = ix {
21290            highlights.insert(ix, range);
21291        }
21292        self.gutter_highlights
21293            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21294    }
21295
21296    pub fn remove_gutter_highlights<T: 'static>(
21297        &mut self,
21298        ranges_to_remove: Vec<Range<Anchor>>,
21299        cx: &mut Context<Self>,
21300    ) {
21301        let snapshot = self.buffer().read(cx).snapshot(cx);
21302        let Some((color_fetcher, mut gutter_highlights)) =
21303            self.gutter_highlights.remove(&TypeId::of::<T>())
21304        else {
21305            return;
21306        };
21307        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21308        gutter_highlights.retain(|highlight| {
21309            while let Some(range_to_remove) = ranges_to_remove.peek() {
21310                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21311                    Ordering::Less | Ordering::Equal => {
21312                        ranges_to_remove.next();
21313                    }
21314                    Ordering::Greater => {
21315                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21316                            Ordering::Less | Ordering::Equal => {
21317                                return false;
21318                            }
21319                            Ordering::Greater => break,
21320                        }
21321                    }
21322                }
21323            }
21324
21325            true
21326        });
21327        self.gutter_highlights
21328            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21329    }
21330
21331    #[cfg(feature = "test-support")]
21332    pub fn all_text_highlights(
21333        &self,
21334        window: &mut Window,
21335        cx: &mut Context<Self>,
21336    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21337        let snapshot = self.snapshot(window, cx);
21338        self.display_map.update(cx, |display_map, _| {
21339            display_map
21340                .all_text_highlights()
21341                .map(|highlight| {
21342                    let (style, ranges) = highlight.as_ref();
21343                    (
21344                        *style,
21345                        ranges
21346                            .iter()
21347                            .map(|range| range.clone().to_display_points(&snapshot))
21348                            .collect(),
21349                    )
21350                })
21351                .collect()
21352        })
21353    }
21354
21355    #[cfg(feature = "test-support")]
21356    pub fn all_text_background_highlights(
21357        &self,
21358        window: &mut Window,
21359        cx: &mut Context<Self>,
21360    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21361        let snapshot = self.snapshot(window, cx);
21362        let buffer = &snapshot.buffer_snapshot();
21363        let start = buffer.anchor_before(MultiBufferOffset(0));
21364        let end = buffer.anchor_after(buffer.len());
21365        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21366    }
21367
21368    #[cfg(any(test, feature = "test-support"))]
21369    pub fn sorted_background_highlights_in_range(
21370        &self,
21371        search_range: Range<Anchor>,
21372        display_snapshot: &DisplaySnapshot,
21373        theme: &Theme,
21374    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21375        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21376        res.sort_by(|a, b| {
21377            a.0.start
21378                .cmp(&b.0.start)
21379                .then_with(|| a.0.end.cmp(&b.0.end))
21380                .then_with(|| a.1.cmp(&b.1))
21381        });
21382        res
21383    }
21384
21385    #[cfg(feature = "test-support")]
21386    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21387        let snapshot = self.buffer().read(cx).snapshot(cx);
21388
21389        let highlights = self
21390            .background_highlights
21391            .get(&HighlightKey::Type(TypeId::of::<
21392                items::BufferSearchHighlights,
21393            >()));
21394
21395        if let Some((_color, ranges)) = highlights {
21396            ranges
21397                .iter()
21398                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21399                .collect_vec()
21400        } else {
21401            vec![]
21402        }
21403    }
21404
21405    fn document_highlights_for_position<'a>(
21406        &'a self,
21407        position: Anchor,
21408        buffer: &'a MultiBufferSnapshot,
21409    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21410        let read_highlights = self
21411            .background_highlights
21412            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21413            .map(|h| &h.1);
21414        let write_highlights = self
21415            .background_highlights
21416            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21417            .map(|h| &h.1);
21418        let left_position = position.bias_left(buffer);
21419        let right_position = position.bias_right(buffer);
21420        read_highlights
21421            .into_iter()
21422            .chain(write_highlights)
21423            .flat_map(move |ranges| {
21424                let start_ix = match ranges.binary_search_by(|probe| {
21425                    let cmp = probe.end.cmp(&left_position, buffer);
21426                    if cmp.is_ge() {
21427                        Ordering::Greater
21428                    } else {
21429                        Ordering::Less
21430                    }
21431                }) {
21432                    Ok(i) | Err(i) => i,
21433                };
21434
21435                ranges[start_ix..]
21436                    .iter()
21437                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21438            })
21439    }
21440
21441    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21442        self.background_highlights
21443            .get(&HighlightKey::Type(TypeId::of::<T>()))
21444            .is_some_and(|(_, highlights)| !highlights.is_empty())
21445    }
21446
21447    /// Returns all background highlights for a given range.
21448    ///
21449    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21450    pub fn background_highlights_in_range(
21451        &self,
21452        search_range: Range<Anchor>,
21453        display_snapshot: &DisplaySnapshot,
21454        theme: &Theme,
21455    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21456        let mut results = Vec::new();
21457        for (color_fetcher, ranges) in self.background_highlights.values() {
21458            let start_ix = match ranges.binary_search_by(|probe| {
21459                let cmp = probe
21460                    .end
21461                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21462                if cmp.is_gt() {
21463                    Ordering::Greater
21464                } else {
21465                    Ordering::Less
21466                }
21467            }) {
21468                Ok(i) | Err(i) => i,
21469            };
21470            for (index, range) in ranges[start_ix..].iter().enumerate() {
21471                if range
21472                    .start
21473                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21474                    .is_ge()
21475                {
21476                    break;
21477                }
21478
21479                let color = color_fetcher(&(start_ix + index), theme);
21480                let start = range.start.to_display_point(display_snapshot);
21481                let end = range.end.to_display_point(display_snapshot);
21482                results.push((start..end, color))
21483            }
21484        }
21485        results
21486    }
21487
21488    pub fn gutter_highlights_in_range(
21489        &self,
21490        search_range: Range<Anchor>,
21491        display_snapshot: &DisplaySnapshot,
21492        cx: &App,
21493    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21494        let mut results = Vec::new();
21495        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21496            let color = color_fetcher(cx);
21497            let start_ix = match ranges.binary_search_by(|probe| {
21498                let cmp = probe
21499                    .end
21500                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21501                if cmp.is_gt() {
21502                    Ordering::Greater
21503                } else {
21504                    Ordering::Less
21505                }
21506            }) {
21507                Ok(i) | Err(i) => i,
21508            };
21509            for range in &ranges[start_ix..] {
21510                if range
21511                    .start
21512                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21513                    .is_ge()
21514                {
21515                    break;
21516                }
21517
21518                let start = range.start.to_display_point(display_snapshot);
21519                let end = range.end.to_display_point(display_snapshot);
21520                results.push((start..end, color))
21521            }
21522        }
21523        results
21524    }
21525
21526    /// Get the text ranges corresponding to the redaction query
21527    pub fn redacted_ranges(
21528        &self,
21529        search_range: Range<Anchor>,
21530        display_snapshot: &DisplaySnapshot,
21531        cx: &App,
21532    ) -> Vec<Range<DisplayPoint>> {
21533        display_snapshot
21534            .buffer_snapshot()
21535            .redacted_ranges(search_range, |file| {
21536                if let Some(file) = file {
21537                    file.is_private()
21538                        && EditorSettings::get(
21539                            Some(SettingsLocation {
21540                                worktree_id: file.worktree_id(cx),
21541                                path: file.path().as_ref(),
21542                            }),
21543                            cx,
21544                        )
21545                        .redact_private_values
21546                } else {
21547                    false
21548                }
21549            })
21550            .map(|range| {
21551                range.start.to_display_point(display_snapshot)
21552                    ..range.end.to_display_point(display_snapshot)
21553            })
21554            .collect()
21555    }
21556
21557    pub fn highlight_text_key<T: 'static>(
21558        &mut self,
21559        key: usize,
21560        ranges: Vec<Range<Anchor>>,
21561        style: HighlightStyle,
21562        merge: bool,
21563        cx: &mut Context<Self>,
21564    ) {
21565        self.display_map.update(cx, |map, cx| {
21566            map.highlight_text(
21567                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21568                ranges,
21569                style,
21570                merge,
21571                cx,
21572            );
21573        });
21574        cx.notify();
21575    }
21576
21577    pub fn highlight_text<T: 'static>(
21578        &mut self,
21579        ranges: Vec<Range<Anchor>>,
21580        style: HighlightStyle,
21581        cx: &mut Context<Self>,
21582    ) {
21583        self.display_map.update(cx, |map, cx| {
21584            map.highlight_text(
21585                HighlightKey::Type(TypeId::of::<T>()),
21586                ranges,
21587                style,
21588                false,
21589                cx,
21590            )
21591        });
21592        cx.notify();
21593    }
21594
21595    pub fn text_highlights<'a, T: 'static>(
21596        &'a self,
21597        cx: &'a App,
21598    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21599        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21600    }
21601
21602    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21603        let cleared = self
21604            .display_map
21605            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21606        if cleared {
21607            cx.notify();
21608        }
21609    }
21610
21611    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21612        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21613            && self.focus_handle.is_focused(window)
21614    }
21615
21616    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21617        self.show_cursor_when_unfocused = is_enabled;
21618        cx.notify();
21619    }
21620
21621    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21622        cx.notify();
21623    }
21624
21625    fn on_debug_session_event(
21626        &mut self,
21627        _session: Entity<Session>,
21628        event: &SessionEvent,
21629        cx: &mut Context<Self>,
21630    ) {
21631        if let SessionEvent::InvalidateInlineValue = event {
21632            self.refresh_inline_values(cx);
21633        }
21634    }
21635
21636    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21637        let Some(project) = self.project.clone() else {
21638            return;
21639        };
21640
21641        if !self.inline_value_cache.enabled {
21642            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21643            self.splice_inlays(&inlays, Vec::new(), cx);
21644            return;
21645        }
21646
21647        let current_execution_position = self
21648            .highlighted_rows
21649            .get(&TypeId::of::<ActiveDebugLine>())
21650            .and_then(|lines| lines.last().map(|line| line.range.end));
21651
21652        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21653            let inline_values = editor
21654                .update(cx, |editor, cx| {
21655                    let Some(current_execution_position) = current_execution_position else {
21656                        return Some(Task::ready(Ok(Vec::new())));
21657                    };
21658
21659                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21660                        let snapshot = buffer.snapshot(cx);
21661
21662                        let excerpt = snapshot.excerpt_containing(
21663                            current_execution_position..current_execution_position,
21664                        )?;
21665
21666                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21667                    })?;
21668
21669                    let range =
21670                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21671
21672                    project.inline_values(buffer, range, cx)
21673                })
21674                .ok()
21675                .flatten()?
21676                .await
21677                .context("refreshing debugger inlays")
21678                .log_err()?;
21679
21680            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21681
21682            for (buffer_id, inline_value) in inline_values
21683                .into_iter()
21684                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21685            {
21686                buffer_inline_values
21687                    .entry(buffer_id)
21688                    .or_default()
21689                    .push(inline_value);
21690            }
21691
21692            editor
21693                .update(cx, |editor, cx| {
21694                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21695                    let mut new_inlays = Vec::default();
21696
21697                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21698                        let buffer_id = buffer_snapshot.remote_id();
21699                        buffer_inline_values
21700                            .get(&buffer_id)
21701                            .into_iter()
21702                            .flatten()
21703                            .for_each(|hint| {
21704                                let inlay = Inlay::debugger(
21705                                    post_inc(&mut editor.next_inlay_id),
21706                                    Anchor::in_buffer(excerpt_id, hint.position),
21707                                    hint.text(),
21708                                );
21709                                if !inlay.text().chars().contains(&'\n') {
21710                                    new_inlays.push(inlay);
21711                                }
21712                            });
21713                    }
21714
21715                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21716                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21717
21718                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21719                })
21720                .ok()?;
21721            Some(())
21722        });
21723    }
21724
21725    fn on_buffer_event(
21726        &mut self,
21727        multibuffer: &Entity<MultiBuffer>,
21728        event: &multi_buffer::Event,
21729        window: &mut Window,
21730        cx: &mut Context<Self>,
21731    ) {
21732        match event {
21733            multi_buffer::Event::Edited { edited_buffer } => {
21734                self.scrollbar_marker_state.dirty = true;
21735                self.active_indent_guides_state.dirty = true;
21736                self.refresh_active_diagnostics(cx);
21737                self.refresh_code_actions(window, cx);
21738                self.refresh_single_line_folds(window, cx);
21739                self.refresh_matching_bracket_highlights(window, cx);
21740                if self.has_active_edit_prediction() {
21741                    self.update_visible_edit_prediction(window, cx);
21742                }
21743
21744                if let Some(buffer) = edited_buffer {
21745                    if buffer.read(cx).file().is_none() {
21746                        cx.emit(EditorEvent::TitleChanged);
21747                    }
21748
21749                    if self.project.is_some() {
21750                        let buffer_id = buffer.read(cx).remote_id();
21751                        self.register_buffer(buffer_id, cx);
21752                        self.update_lsp_data(Some(buffer_id), window, cx);
21753                        self.refresh_inlay_hints(
21754                            InlayHintRefreshReason::BufferEdited(buffer_id),
21755                            cx,
21756                        );
21757                    }
21758                }
21759
21760                cx.emit(EditorEvent::BufferEdited);
21761                cx.emit(SearchEvent::MatchesInvalidated);
21762
21763                let Some(project) = &self.project else { return };
21764                let (telemetry, is_via_ssh) = {
21765                    let project = project.read(cx);
21766                    let telemetry = project.client().telemetry().clone();
21767                    let is_via_ssh = project.is_via_remote_server();
21768                    (telemetry, is_via_ssh)
21769                };
21770                telemetry.log_edit_event("editor", is_via_ssh);
21771            }
21772            multi_buffer::Event::ExcerptsAdded {
21773                buffer,
21774                predecessor,
21775                excerpts,
21776            } => {
21777                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21778                let buffer_id = buffer.read(cx).remote_id();
21779                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21780                    && let Some(project) = &self.project
21781                {
21782                    update_uncommitted_diff_for_buffer(
21783                        cx.entity(),
21784                        project,
21785                        [buffer.clone()],
21786                        self.buffer.clone(),
21787                        cx,
21788                    )
21789                    .detach();
21790                }
21791                self.update_lsp_data(Some(buffer_id), window, cx);
21792                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21793                self.colorize_brackets(false, cx);
21794                cx.emit(EditorEvent::ExcerptsAdded {
21795                    buffer: buffer.clone(),
21796                    predecessor: *predecessor,
21797                    excerpts: excerpts.clone(),
21798                });
21799            }
21800            multi_buffer::Event::ExcerptsRemoved {
21801                ids,
21802                removed_buffer_ids,
21803            } => {
21804                if let Some(inlay_hints) = &mut self.inlay_hints {
21805                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21806                }
21807                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21808                for buffer_id in removed_buffer_ids {
21809                    self.registered_buffers.remove(buffer_id);
21810                }
21811                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21812                cx.emit(EditorEvent::ExcerptsRemoved {
21813                    ids: ids.clone(),
21814                    removed_buffer_ids: removed_buffer_ids.clone(),
21815                });
21816            }
21817            multi_buffer::Event::ExcerptsEdited {
21818                excerpt_ids,
21819                buffer_ids,
21820            } => {
21821                self.display_map.update(cx, |map, cx| {
21822                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21823                });
21824                cx.emit(EditorEvent::ExcerptsEdited {
21825                    ids: excerpt_ids.clone(),
21826                });
21827            }
21828            multi_buffer::Event::ExcerptsExpanded { ids } => {
21829                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21830                self.refresh_document_highlights(cx);
21831                for id in ids {
21832                    self.fetched_tree_sitter_chunks.remove(id);
21833                }
21834                self.colorize_brackets(false, cx);
21835                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21836            }
21837            multi_buffer::Event::Reparsed(buffer_id) => {
21838                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21839                self.refresh_selected_text_highlights(true, window, cx);
21840                self.colorize_brackets(true, cx);
21841                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21842
21843                cx.emit(EditorEvent::Reparsed(*buffer_id));
21844            }
21845            multi_buffer::Event::DiffHunksToggled => {
21846                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21847            }
21848            multi_buffer::Event::LanguageChanged(buffer_id) => {
21849                self.registered_buffers.remove(&buffer_id);
21850                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21851                cx.emit(EditorEvent::Reparsed(*buffer_id));
21852                cx.notify();
21853            }
21854            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21855            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21856            multi_buffer::Event::FileHandleChanged
21857            | multi_buffer::Event::Reloaded
21858            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21859            multi_buffer::Event::DiagnosticsUpdated => {
21860                self.update_diagnostics_state(window, cx);
21861            }
21862            _ => {}
21863        };
21864    }
21865
21866    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21867        if !self.diagnostics_enabled() {
21868            return;
21869        }
21870        self.refresh_active_diagnostics(cx);
21871        self.refresh_inline_diagnostics(true, window, cx);
21872        self.scrollbar_marker_state.dirty = true;
21873        cx.notify();
21874    }
21875
21876    pub fn start_temporary_diff_override(&mut self) {
21877        self.load_diff_task.take();
21878        self.temporary_diff_override = true;
21879    }
21880
21881    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21882        self.temporary_diff_override = false;
21883        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21884        self.buffer.update(cx, |buffer, cx| {
21885            buffer.set_all_diff_hunks_collapsed(cx);
21886        });
21887
21888        if let Some(project) = self.project.clone() {
21889            self.load_diff_task = Some(
21890                update_uncommitted_diff_for_buffer(
21891                    cx.entity(),
21892                    &project,
21893                    self.buffer.read(cx).all_buffers(),
21894                    self.buffer.clone(),
21895                    cx,
21896                )
21897                .shared(),
21898            );
21899        }
21900    }
21901
21902    fn on_display_map_changed(
21903        &mut self,
21904        _: Entity<DisplayMap>,
21905        _: &mut Window,
21906        cx: &mut Context<Self>,
21907    ) {
21908        cx.notify();
21909    }
21910
21911    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
21912        if !self.mode.is_full() {
21913            return None;
21914        }
21915
21916        let theme_settings = theme::ThemeSettings::get_global(cx);
21917        let theme = cx.theme();
21918        let accent_colors = theme.accents().clone();
21919
21920        let accent_overrides = theme_settings
21921            .theme_overrides
21922            .get(theme.name.as_ref())
21923            .map(|theme_style| &theme_style.accents)
21924            .into_iter()
21925            .flatten()
21926            .chain(
21927                theme_settings
21928                    .experimental_theme_overrides
21929                    .as_ref()
21930                    .map(|overrides| &overrides.accents)
21931                    .into_iter()
21932                    .flatten(),
21933            )
21934            .flat_map(|accent| accent.0.clone())
21935            .collect();
21936
21937        Some(AccentData {
21938            colors: accent_colors,
21939            overrides: accent_overrides,
21940        })
21941    }
21942
21943    fn fetch_applicable_language_settings(
21944        &self,
21945        cx: &App,
21946    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
21947        if !self.mode.is_full() {
21948            return HashMap::default();
21949        }
21950
21951        self.buffer().read(cx).all_buffers().into_iter().fold(
21952            HashMap::default(),
21953            |mut acc, buffer| {
21954                let buffer = buffer.read(cx);
21955                let language = buffer.language().map(|language| language.name());
21956                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
21957                    let file = buffer.file();
21958                    v.insert(language_settings(language, file, cx).into_owned());
21959                }
21960                acc
21961            },
21962        )
21963    }
21964
21965    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21966        let new_language_settings = self.fetch_applicable_language_settings(cx);
21967        let language_settings_changed = new_language_settings != self.applicable_language_settings;
21968        self.applicable_language_settings = new_language_settings;
21969
21970        let new_accents = self.fetch_accent_data(cx);
21971        let accents_changed = new_accents != self.accent_data;
21972        self.accent_data = new_accents;
21973
21974        if self.diagnostics_enabled() {
21975            let new_severity = EditorSettings::get_global(cx)
21976                .diagnostics_max_severity
21977                .unwrap_or(DiagnosticSeverity::Hint);
21978            self.set_max_diagnostics_severity(new_severity, cx);
21979        }
21980        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21981        self.update_edit_prediction_settings(cx);
21982        self.refresh_edit_prediction(true, false, window, cx);
21983        self.refresh_inline_values(cx);
21984        self.refresh_inlay_hints(
21985            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21986                self.selections.newest_anchor().head(),
21987                &self.buffer.read(cx).snapshot(cx),
21988                cx,
21989            )),
21990            cx,
21991        );
21992
21993        let old_cursor_shape = self.cursor_shape;
21994        let old_show_breadcrumbs = self.show_breadcrumbs;
21995
21996        {
21997            let editor_settings = EditorSettings::get_global(cx);
21998            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21999            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22000            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22001            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22002        }
22003
22004        if old_cursor_shape != self.cursor_shape {
22005            cx.emit(EditorEvent::CursorShapeChanged);
22006        }
22007
22008        if old_show_breadcrumbs != self.show_breadcrumbs {
22009            cx.emit(EditorEvent::BreadcrumbsChanged);
22010        }
22011
22012        let project_settings = ProjectSettings::get_global(cx);
22013        self.buffer_serialization = self
22014            .should_serialize_buffer()
22015            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22016
22017        if self.mode.is_full() {
22018            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22019            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22020            if self.show_inline_diagnostics != show_inline_diagnostics {
22021                self.show_inline_diagnostics = show_inline_diagnostics;
22022                self.refresh_inline_diagnostics(false, window, cx);
22023            }
22024
22025            if self.git_blame_inline_enabled != inline_blame_enabled {
22026                self.toggle_git_blame_inline_internal(false, window, cx);
22027            }
22028
22029            let minimap_settings = EditorSettings::get_global(cx).minimap;
22030            if self.minimap_visibility != MinimapVisibility::Disabled {
22031                if self.minimap_visibility.settings_visibility()
22032                    != minimap_settings.minimap_enabled()
22033                {
22034                    self.set_minimap_visibility(
22035                        MinimapVisibility::for_mode(self.mode(), cx),
22036                        window,
22037                        cx,
22038                    );
22039                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22040                    minimap_entity.update(cx, |minimap_editor, cx| {
22041                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22042                    })
22043                }
22044            }
22045
22046            if language_settings_changed || accents_changed {
22047                self.colorize_brackets(true, cx);
22048            }
22049
22050            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22051                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22052            }) {
22053                if !inlay_splice.is_empty() {
22054                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22055                }
22056                self.refresh_colors_for_visible_range(None, window, cx);
22057            }
22058        }
22059
22060        cx.notify();
22061    }
22062
22063    pub fn set_searchable(&mut self, searchable: bool) {
22064        self.searchable = searchable;
22065    }
22066
22067    pub fn searchable(&self) -> bool {
22068        self.searchable
22069    }
22070
22071    pub fn open_excerpts_in_split(
22072        &mut self,
22073        _: &OpenExcerptsSplit,
22074        window: &mut Window,
22075        cx: &mut Context<Self>,
22076    ) {
22077        self.open_excerpts_common(None, true, window, cx)
22078    }
22079
22080    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22081        self.open_excerpts_common(None, false, window, cx)
22082    }
22083
22084    fn open_excerpts_common(
22085        &mut self,
22086        jump_data: Option<JumpData>,
22087        split: bool,
22088        window: &mut Window,
22089        cx: &mut Context<Self>,
22090    ) {
22091        let Some(workspace) = self.workspace() else {
22092            cx.propagate();
22093            return;
22094        };
22095
22096        if self.buffer.read(cx).is_singleton() {
22097            cx.propagate();
22098            return;
22099        }
22100
22101        let mut new_selections_by_buffer = HashMap::default();
22102        match &jump_data {
22103            Some(JumpData::MultiBufferPoint {
22104                excerpt_id,
22105                position,
22106                anchor,
22107                line_offset_from_top,
22108            }) => {
22109                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22110                if let Some(buffer) = multi_buffer_snapshot
22111                    .buffer_id_for_excerpt(*excerpt_id)
22112                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22113                {
22114                    let buffer_snapshot = buffer.read(cx).snapshot();
22115                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22116                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22117                    } else {
22118                        buffer_snapshot.clip_point(*position, Bias::Left)
22119                    };
22120                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22121                    new_selections_by_buffer.insert(
22122                        buffer,
22123                        (
22124                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22125                            Some(*line_offset_from_top),
22126                        ),
22127                    );
22128                }
22129            }
22130            Some(JumpData::MultiBufferRow {
22131                row,
22132                line_offset_from_top,
22133            }) => {
22134                let point = MultiBufferPoint::new(row.0, 0);
22135                if let Some((buffer, buffer_point, _)) =
22136                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22137                {
22138                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22139                    new_selections_by_buffer
22140                        .entry(buffer)
22141                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22142                        .0
22143                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22144                }
22145            }
22146            None => {
22147                let selections = self
22148                    .selections
22149                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22150                let multi_buffer = self.buffer.read(cx);
22151                for selection in selections {
22152                    for (snapshot, range, _, anchor) in multi_buffer
22153                        .snapshot(cx)
22154                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22155                    {
22156                        if let Some(anchor) = anchor {
22157                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22158                            else {
22159                                continue;
22160                            };
22161                            let offset = text::ToOffset::to_offset(
22162                                &anchor.text_anchor,
22163                                &buffer_handle.read(cx).snapshot(),
22164                            );
22165                            let range = BufferOffset(offset)..BufferOffset(offset);
22166                            new_selections_by_buffer
22167                                .entry(buffer_handle)
22168                                .or_insert((Vec::new(), None))
22169                                .0
22170                                .push(range)
22171                        } else {
22172                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22173                            else {
22174                                continue;
22175                            };
22176                            new_selections_by_buffer
22177                                .entry(buffer_handle)
22178                                .or_insert((Vec::new(), None))
22179                                .0
22180                                .push(range)
22181                        }
22182                    }
22183                }
22184            }
22185        }
22186
22187        new_selections_by_buffer
22188            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22189
22190        if new_selections_by_buffer.is_empty() {
22191            return;
22192        }
22193
22194        // We defer the pane interaction because we ourselves are a workspace item
22195        // and activating a new item causes the pane to call a method on us reentrantly,
22196        // which panics if we're on the stack.
22197        window.defer(cx, move |window, cx| {
22198            workspace.update(cx, |workspace, cx| {
22199                let pane = if split {
22200                    workspace.adjacent_pane(window, cx)
22201                } else {
22202                    workspace.active_pane().clone()
22203                };
22204
22205                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22206                    let buffer_read = buffer.read(cx);
22207                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22208                        (true, project::File::from_dyn(Some(file)).is_some())
22209                    } else {
22210                        (false, false)
22211                    };
22212
22213                    // If project file is none workspace.open_project_item will fail to open the excerpt
22214                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22215                    // so we check if there's a tab match in that case first
22216                    let editor = (!has_file || !is_project_file)
22217                        .then(|| {
22218                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22219                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22220                            // Instead, we try to activate the existing editor in the pane first.
22221                            let (editor, pane_item_index, pane_item_id) =
22222                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22223                                    let editor = item.downcast::<Editor>()?;
22224                                    let singleton_buffer =
22225                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22226                                    if singleton_buffer == buffer {
22227                                        Some((editor, i, item.item_id()))
22228                                    } else {
22229                                        None
22230                                    }
22231                                })?;
22232                            pane.update(cx, |pane, cx| {
22233                                pane.activate_item(pane_item_index, true, true, window, cx);
22234                                if !PreviewTabsSettings::get_global(cx)
22235                                    .enable_preview_from_multibuffer
22236                                {
22237                                    pane.unpreview_item_if_preview(pane_item_id);
22238                                }
22239                            });
22240                            Some(editor)
22241                        })
22242                        .flatten()
22243                        .unwrap_or_else(|| {
22244                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22245                                .enable_keep_preview_on_code_navigation;
22246                            let allow_new_preview =
22247                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22248                            workspace.open_project_item::<Self>(
22249                                pane.clone(),
22250                                buffer,
22251                                true,
22252                                true,
22253                                keep_old_preview,
22254                                allow_new_preview,
22255                                window,
22256                                cx,
22257                            )
22258                        });
22259
22260                    editor.update(cx, |editor, cx| {
22261                        if has_file && !is_project_file {
22262                            editor.set_read_only(true);
22263                        }
22264                        let autoscroll = match scroll_offset {
22265                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22266                            None => Autoscroll::newest(),
22267                        };
22268                        let nav_history = editor.nav_history.take();
22269                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22270                        let Some((&excerpt_id, _, buffer_snapshot)) =
22271                            multibuffer_snapshot.as_singleton()
22272                        else {
22273                            return;
22274                        };
22275                        editor.change_selections(
22276                            SelectionEffects::scroll(autoscroll),
22277                            window,
22278                            cx,
22279                            |s| {
22280                                s.select_ranges(ranges.into_iter().map(|range| {
22281                                    let range = buffer_snapshot.anchor_before(range.start)
22282                                        ..buffer_snapshot.anchor_after(range.end);
22283                                    multibuffer_snapshot
22284                                        .anchor_range_in_excerpt(excerpt_id, range)
22285                                        .unwrap()
22286                                }));
22287                            },
22288                        );
22289                        editor.nav_history = nav_history;
22290                    });
22291                }
22292            })
22293        });
22294    }
22295
22296    // Allow opening excerpts for buffers that either belong to the current project
22297    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22298    // are also supported so tests and other in-memory views keep working.
22299    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22300        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22301    }
22302
22303    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22304        let snapshot = self.buffer.read(cx).read(cx);
22305        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22306        Some(
22307            ranges
22308                .iter()
22309                .map(move |range| {
22310                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22311                })
22312                .collect(),
22313        )
22314    }
22315
22316    fn selection_replacement_ranges(
22317        &self,
22318        range: Range<MultiBufferOffsetUtf16>,
22319        cx: &mut App,
22320    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22321        let selections = self
22322            .selections
22323            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22324        let newest_selection = selections
22325            .iter()
22326            .max_by_key(|selection| selection.id)
22327            .unwrap();
22328        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22329        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22330        let snapshot = self.buffer.read(cx).read(cx);
22331        selections
22332            .into_iter()
22333            .map(|mut selection| {
22334                selection.start.0.0 =
22335                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22336                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22337                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22338                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22339            })
22340            .collect()
22341    }
22342
22343    fn report_editor_event(
22344        &self,
22345        reported_event: ReportEditorEvent,
22346        file_extension: Option<String>,
22347        cx: &App,
22348    ) {
22349        if cfg!(any(test, feature = "test-support")) {
22350            return;
22351        }
22352
22353        let Some(project) = &self.project else { return };
22354
22355        // If None, we are in a file without an extension
22356        let file = self
22357            .buffer
22358            .read(cx)
22359            .as_singleton()
22360            .and_then(|b| b.read(cx).file());
22361        let file_extension = file_extension.or(file
22362            .as_ref()
22363            .and_then(|file| Path::new(file.file_name(cx)).extension())
22364            .and_then(|e| e.to_str())
22365            .map(|a| a.to_string()));
22366
22367        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22368            .map(|vim_mode| vim_mode.0)
22369            .unwrap_or(false);
22370
22371        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22372        let copilot_enabled = edit_predictions_provider
22373            == language::language_settings::EditPredictionProvider::Copilot;
22374        let copilot_enabled_for_language = self
22375            .buffer
22376            .read(cx)
22377            .language_settings(cx)
22378            .show_edit_predictions;
22379
22380        let project = project.read(cx);
22381        let event_type = reported_event.event_type();
22382
22383        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22384            telemetry::event!(
22385                event_type,
22386                type = if auto_saved {"autosave"} else {"manual"},
22387                file_extension,
22388                vim_mode,
22389                copilot_enabled,
22390                copilot_enabled_for_language,
22391                edit_predictions_provider,
22392                is_via_ssh = project.is_via_remote_server(),
22393            );
22394        } else {
22395            telemetry::event!(
22396                event_type,
22397                file_extension,
22398                vim_mode,
22399                copilot_enabled,
22400                copilot_enabled_for_language,
22401                edit_predictions_provider,
22402                is_via_ssh = project.is_via_remote_server(),
22403            );
22404        };
22405    }
22406
22407    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22408    /// with each line being an array of {text, highlight} objects.
22409    fn copy_highlight_json(
22410        &mut self,
22411        _: &CopyHighlightJson,
22412        window: &mut Window,
22413        cx: &mut Context<Self>,
22414    ) {
22415        #[derive(Serialize)]
22416        struct Chunk<'a> {
22417            text: String,
22418            highlight: Option<&'a str>,
22419        }
22420
22421        let snapshot = self.buffer.read(cx).snapshot(cx);
22422        let range = self
22423            .selected_text_range(false, window, cx)
22424            .and_then(|selection| {
22425                if selection.range.is_empty() {
22426                    None
22427                } else {
22428                    Some(
22429                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22430                            selection.range.start,
22431                        )))
22432                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22433                                selection.range.end,
22434                            ))),
22435                    )
22436                }
22437            })
22438            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22439
22440        let chunks = snapshot.chunks(range, true);
22441        let mut lines = Vec::new();
22442        let mut line: VecDeque<Chunk> = VecDeque::new();
22443
22444        let Some(style) = self.style.as_ref() else {
22445            return;
22446        };
22447
22448        for chunk in chunks {
22449            let highlight = chunk
22450                .syntax_highlight_id
22451                .and_then(|id| id.name(&style.syntax));
22452            let mut chunk_lines = chunk.text.split('\n').peekable();
22453            while let Some(text) = chunk_lines.next() {
22454                let mut merged_with_last_token = false;
22455                if let Some(last_token) = line.back_mut()
22456                    && last_token.highlight == highlight
22457                {
22458                    last_token.text.push_str(text);
22459                    merged_with_last_token = true;
22460                }
22461
22462                if !merged_with_last_token {
22463                    line.push_back(Chunk {
22464                        text: text.into(),
22465                        highlight,
22466                    });
22467                }
22468
22469                if chunk_lines.peek().is_some() {
22470                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22471                        line.pop_front();
22472                    }
22473                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22474                        line.pop_back();
22475                    }
22476
22477                    lines.push(mem::take(&mut line));
22478                }
22479            }
22480        }
22481
22482        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22483            return;
22484        };
22485        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22486    }
22487
22488    pub fn open_context_menu(
22489        &mut self,
22490        _: &OpenContextMenu,
22491        window: &mut Window,
22492        cx: &mut Context<Self>,
22493    ) {
22494        self.request_autoscroll(Autoscroll::newest(), cx);
22495        let position = self
22496            .selections
22497            .newest_display(&self.display_snapshot(cx))
22498            .start;
22499        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22500    }
22501
22502    pub fn replay_insert_event(
22503        &mut self,
22504        text: &str,
22505        relative_utf16_range: Option<Range<isize>>,
22506        window: &mut Window,
22507        cx: &mut Context<Self>,
22508    ) {
22509        if !self.input_enabled {
22510            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22511            return;
22512        }
22513        if let Some(relative_utf16_range) = relative_utf16_range {
22514            let selections = self
22515                .selections
22516                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22517            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22518                let new_ranges = selections.into_iter().map(|range| {
22519                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22520                        range
22521                            .head()
22522                            .0
22523                            .0
22524                            .saturating_add_signed(relative_utf16_range.start),
22525                    ));
22526                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22527                        range
22528                            .head()
22529                            .0
22530                            .0
22531                            .saturating_add_signed(relative_utf16_range.end),
22532                    ));
22533                    start..end
22534                });
22535                s.select_ranges(new_ranges);
22536            });
22537        }
22538
22539        self.handle_input(text, window, cx);
22540    }
22541
22542    pub fn is_focused(&self, window: &Window) -> bool {
22543        self.focus_handle.is_focused(window)
22544    }
22545
22546    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22547        cx.emit(EditorEvent::Focused);
22548
22549        if let Some(descendant) = self
22550            .last_focused_descendant
22551            .take()
22552            .and_then(|descendant| descendant.upgrade())
22553        {
22554            window.focus(&descendant);
22555        } else {
22556            if let Some(blame) = self.blame.as_ref() {
22557                blame.update(cx, GitBlame::focus)
22558            }
22559
22560            self.blink_manager.update(cx, BlinkManager::enable);
22561            self.show_cursor_names(window, cx);
22562            self.buffer.update(cx, |buffer, cx| {
22563                buffer.finalize_last_transaction(cx);
22564                if self.leader_id.is_none() {
22565                    buffer.set_active_selections(
22566                        &self.selections.disjoint_anchors_arc(),
22567                        self.selections.line_mode(),
22568                        self.cursor_shape,
22569                        cx,
22570                    );
22571                }
22572            });
22573
22574            if let Some(position_map) = self.last_position_map.clone() {
22575                EditorElement::mouse_moved(
22576                    self,
22577                    &MouseMoveEvent {
22578                        position: window.mouse_position(),
22579                        pressed_button: None,
22580                        modifiers: window.modifiers(),
22581                    },
22582                    &position_map,
22583                    window,
22584                    cx,
22585                );
22586            }
22587        }
22588    }
22589
22590    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22591        cx.emit(EditorEvent::FocusedIn)
22592    }
22593
22594    fn handle_focus_out(
22595        &mut self,
22596        event: FocusOutEvent,
22597        _window: &mut Window,
22598        cx: &mut Context<Self>,
22599    ) {
22600        if event.blurred != self.focus_handle {
22601            self.last_focused_descendant = Some(event.blurred);
22602        }
22603        self.selection_drag_state = SelectionDragState::None;
22604        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22605    }
22606
22607    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22608        self.blink_manager.update(cx, BlinkManager::disable);
22609        self.buffer
22610            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22611
22612        if let Some(blame) = self.blame.as_ref() {
22613            blame.update(cx, GitBlame::blur)
22614        }
22615        if !self.hover_state.focused(window, cx) {
22616            hide_hover(self, cx);
22617        }
22618        if !self
22619            .context_menu
22620            .borrow()
22621            .as_ref()
22622            .is_some_and(|context_menu| context_menu.focused(window, cx))
22623        {
22624            self.hide_context_menu(window, cx);
22625        }
22626        self.take_active_edit_prediction(cx);
22627        cx.emit(EditorEvent::Blurred);
22628        cx.notify();
22629    }
22630
22631    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22632        let mut pending: String = window
22633            .pending_input_keystrokes()
22634            .into_iter()
22635            .flatten()
22636            .filter_map(|keystroke| keystroke.key_char.clone())
22637            .collect();
22638
22639        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22640            pending = "".to_string();
22641        }
22642
22643        let existing_pending = self
22644            .text_highlights::<PendingInput>(cx)
22645            .map(|(_, ranges)| ranges.to_vec());
22646        if existing_pending.is_none() && pending.is_empty() {
22647            return;
22648        }
22649        let transaction =
22650            self.transact(window, cx, |this, window, cx| {
22651                let selections = this
22652                    .selections
22653                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22654                let edits = selections
22655                    .iter()
22656                    .map(|selection| (selection.end..selection.end, pending.clone()));
22657                this.edit(edits, cx);
22658                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22659                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22660                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22661                    }));
22662                });
22663                if let Some(existing_ranges) = existing_pending {
22664                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22665                    this.edit(edits, cx);
22666                }
22667            });
22668
22669        let snapshot = self.snapshot(window, cx);
22670        let ranges = self
22671            .selections
22672            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22673            .into_iter()
22674            .map(|selection| {
22675                snapshot.buffer_snapshot().anchor_after(selection.end)
22676                    ..snapshot
22677                        .buffer_snapshot()
22678                        .anchor_before(selection.end + pending.len())
22679            })
22680            .collect();
22681
22682        if pending.is_empty() {
22683            self.clear_highlights::<PendingInput>(cx);
22684        } else {
22685            self.highlight_text::<PendingInput>(
22686                ranges,
22687                HighlightStyle {
22688                    underline: Some(UnderlineStyle {
22689                        thickness: px(1.),
22690                        color: None,
22691                        wavy: false,
22692                    }),
22693                    ..Default::default()
22694                },
22695                cx,
22696            );
22697        }
22698
22699        self.ime_transaction = self.ime_transaction.or(transaction);
22700        if let Some(transaction) = self.ime_transaction {
22701            self.buffer.update(cx, |buffer, cx| {
22702                buffer.group_until_transaction(transaction, cx);
22703            });
22704        }
22705
22706        if self.text_highlights::<PendingInput>(cx).is_none() {
22707            self.ime_transaction.take();
22708        }
22709    }
22710
22711    pub fn register_action_renderer(
22712        &mut self,
22713        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22714    ) -> Subscription {
22715        let id = self.next_editor_action_id.post_inc();
22716        self.editor_actions
22717            .borrow_mut()
22718            .insert(id, Box::new(listener));
22719
22720        let editor_actions = self.editor_actions.clone();
22721        Subscription::new(move || {
22722            editor_actions.borrow_mut().remove(&id);
22723        })
22724    }
22725
22726    pub fn register_action<A: Action>(
22727        &mut self,
22728        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22729    ) -> Subscription {
22730        let id = self.next_editor_action_id.post_inc();
22731        let listener = Arc::new(listener);
22732        self.editor_actions.borrow_mut().insert(
22733            id,
22734            Box::new(move |_, window, _| {
22735                let listener = listener.clone();
22736                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22737                    let action = action.downcast_ref().unwrap();
22738                    if phase == DispatchPhase::Bubble {
22739                        listener(action, window, cx)
22740                    }
22741                })
22742            }),
22743        );
22744
22745        let editor_actions = self.editor_actions.clone();
22746        Subscription::new(move || {
22747            editor_actions.borrow_mut().remove(&id);
22748        })
22749    }
22750
22751    pub fn file_header_size(&self) -> u32 {
22752        FILE_HEADER_HEIGHT
22753    }
22754
22755    pub fn restore(
22756        &mut self,
22757        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22758        window: &mut Window,
22759        cx: &mut Context<Self>,
22760    ) {
22761        let workspace = self.workspace();
22762        let project = self.project();
22763        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22764            let mut tasks = Vec::new();
22765            for (buffer_id, changes) in revert_changes {
22766                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22767                    buffer.update(cx, |buffer, cx| {
22768                        buffer.edit(
22769                            changes
22770                                .into_iter()
22771                                .map(|(range, text)| (range, text.to_string())),
22772                            None,
22773                            cx,
22774                        );
22775                    });
22776
22777                    if let Some(project) =
22778                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22779                    {
22780                        project.update(cx, |project, cx| {
22781                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22782                        })
22783                    }
22784                }
22785            }
22786            tasks
22787        });
22788        cx.spawn_in(window, async move |_, cx| {
22789            for (buffer, task) in save_tasks {
22790                let result = task.await;
22791                if result.is_err() {
22792                    let Some(path) = buffer
22793                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22794                        .ok()
22795                    else {
22796                        continue;
22797                    };
22798                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22799                        let Some(task) = cx
22800                            .update_window_entity(workspace, |workspace, window, cx| {
22801                                workspace
22802                                    .open_path_preview(path, None, false, false, false, window, cx)
22803                            })
22804                            .ok()
22805                        else {
22806                            continue;
22807                        };
22808                        task.await.log_err();
22809                    }
22810                }
22811            }
22812        })
22813        .detach();
22814        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22815            selections.refresh()
22816        });
22817    }
22818
22819    pub fn to_pixel_point(
22820        &self,
22821        source: multi_buffer::Anchor,
22822        editor_snapshot: &EditorSnapshot,
22823        window: &mut Window,
22824    ) -> Option<gpui::Point<Pixels>> {
22825        let source_point = source.to_display_point(editor_snapshot);
22826        self.display_to_pixel_point(source_point, editor_snapshot, window)
22827    }
22828
22829    pub fn display_to_pixel_point(
22830        &self,
22831        source: DisplayPoint,
22832        editor_snapshot: &EditorSnapshot,
22833        window: &mut Window,
22834    ) -> Option<gpui::Point<Pixels>> {
22835        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22836        let text_layout_details = self.text_layout_details(window);
22837        let scroll_top = text_layout_details
22838            .scroll_anchor
22839            .scroll_position(editor_snapshot)
22840            .y;
22841
22842        if source.row().as_f64() < scroll_top.floor() {
22843            return None;
22844        }
22845        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22846        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22847        Some(gpui::Point::new(source_x, source_y))
22848    }
22849
22850    pub fn has_visible_completions_menu(&self) -> bool {
22851        !self.edit_prediction_preview_is_active()
22852            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22853                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22854            })
22855    }
22856
22857    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22858        if self.mode.is_minimap() {
22859            return;
22860        }
22861        self.addons
22862            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22863    }
22864
22865    pub fn unregister_addon<T: Addon>(&mut self) {
22866        self.addons.remove(&std::any::TypeId::of::<T>());
22867    }
22868
22869    pub fn addon<T: Addon>(&self) -> Option<&T> {
22870        let type_id = std::any::TypeId::of::<T>();
22871        self.addons
22872            .get(&type_id)
22873            .and_then(|item| item.to_any().downcast_ref::<T>())
22874    }
22875
22876    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22877        let type_id = std::any::TypeId::of::<T>();
22878        self.addons
22879            .get_mut(&type_id)
22880            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22881    }
22882
22883    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22884        let text_layout_details = self.text_layout_details(window);
22885        let style = &text_layout_details.editor_style;
22886        let font_id = window.text_system().resolve_font(&style.text.font());
22887        let font_size = style.text.font_size.to_pixels(window.rem_size());
22888        let line_height = style.text.line_height_in_pixels(window.rem_size());
22889        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22890        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22891
22892        CharacterDimensions {
22893            em_width,
22894            em_advance,
22895            line_height,
22896        }
22897    }
22898
22899    pub fn last_gutter_dimensions(&self) -> &GutterDimensions {
22900        &self.gutter_dimensions
22901    }
22902
22903    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22904        self.load_diff_task.clone()
22905    }
22906
22907    fn read_metadata_from_db(
22908        &mut self,
22909        item_id: u64,
22910        workspace_id: WorkspaceId,
22911        window: &mut Window,
22912        cx: &mut Context<Editor>,
22913    ) {
22914        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22915            && !self.mode.is_minimap()
22916            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22917        {
22918            let buffer_snapshot = OnceCell::new();
22919
22920            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22921                && !folds.is_empty()
22922            {
22923                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22924                self.fold_ranges(
22925                    folds
22926                        .into_iter()
22927                        .map(|(start, end)| {
22928                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22929                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22930                        })
22931                        .collect(),
22932                    false,
22933                    window,
22934                    cx,
22935                );
22936            }
22937
22938            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22939                && !selections.is_empty()
22940            {
22941                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22942                // skip adding the initial selection to selection history
22943                self.selection_history.mode = SelectionHistoryMode::Skipping;
22944                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22945                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22946                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22947                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22948                    }));
22949                });
22950                self.selection_history.mode = SelectionHistoryMode::Normal;
22951            };
22952        }
22953
22954        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22955    }
22956
22957    fn update_lsp_data(
22958        &mut self,
22959        for_buffer: Option<BufferId>,
22960        window: &mut Window,
22961        cx: &mut Context<'_, Self>,
22962    ) {
22963        self.pull_diagnostics(for_buffer, window, cx);
22964        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22965    }
22966
22967    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22968        if self.ignore_lsp_data() {
22969            return;
22970        }
22971        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
22972            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22973        }
22974    }
22975
22976    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22977        if self.ignore_lsp_data() {
22978            return;
22979        }
22980
22981        if !self.registered_buffers.contains_key(&buffer_id)
22982            && let Some(project) = self.project.as_ref()
22983        {
22984            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22985                project.update(cx, |project, cx| {
22986                    self.registered_buffers.insert(
22987                        buffer_id,
22988                        project.register_buffer_with_language_servers(&buffer, cx),
22989                    );
22990                });
22991            } else {
22992                self.registered_buffers.remove(&buffer_id);
22993            }
22994        }
22995    }
22996
22997    fn ignore_lsp_data(&self) -> bool {
22998        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22999        // skip any LSP updates for it.
23000        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23001    }
23002}
23003
23004fn edit_for_markdown_paste<'a>(
23005    buffer: &MultiBufferSnapshot,
23006    range: Range<MultiBufferOffset>,
23007    to_insert: &'a str,
23008    url: Option<url::Url>,
23009) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23010    if url.is_none() {
23011        return (range, Cow::Borrowed(to_insert));
23012    };
23013
23014    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23015
23016    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23017        Cow::Borrowed(to_insert)
23018    } else {
23019        Cow::Owned(format!("[{old_text}]({to_insert})"))
23020    };
23021    (range, new_text)
23022}
23023
23024fn process_completion_for_edit(
23025    completion: &Completion,
23026    intent: CompletionIntent,
23027    buffer: &Entity<Buffer>,
23028    cursor_position: &text::Anchor,
23029    cx: &mut Context<Editor>,
23030) -> CompletionEdit {
23031    let buffer = buffer.read(cx);
23032    let buffer_snapshot = buffer.snapshot();
23033    let (snippet, new_text) = if completion.is_snippet() {
23034        let mut snippet_source = completion.new_text.clone();
23035        // Workaround for typescript language server issues so that methods don't expand within
23036        // strings and functions with type expressions. The previous point is used because the query
23037        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23038        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23039        let previous_point = if previous_point.column > 0 {
23040            cursor_position.to_previous_offset(&buffer_snapshot)
23041        } else {
23042            cursor_position.to_offset(&buffer_snapshot)
23043        };
23044        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23045            && scope.prefers_label_for_snippet_in_completion()
23046            && let Some(label) = completion.label()
23047            && matches!(
23048                completion.kind(),
23049                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23050            )
23051        {
23052            snippet_source = label;
23053        }
23054        match Snippet::parse(&snippet_source).log_err() {
23055            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23056            None => (None, completion.new_text.clone()),
23057        }
23058    } else {
23059        (None, completion.new_text.clone())
23060    };
23061
23062    let mut range_to_replace = {
23063        let replace_range = &completion.replace_range;
23064        if let CompletionSource::Lsp {
23065            insert_range: Some(insert_range),
23066            ..
23067        } = &completion.source
23068        {
23069            debug_assert_eq!(
23070                insert_range.start, replace_range.start,
23071                "insert_range and replace_range should start at the same position"
23072            );
23073            debug_assert!(
23074                insert_range
23075                    .start
23076                    .cmp(cursor_position, &buffer_snapshot)
23077                    .is_le(),
23078                "insert_range should start before or at cursor position"
23079            );
23080            debug_assert!(
23081                replace_range
23082                    .start
23083                    .cmp(cursor_position, &buffer_snapshot)
23084                    .is_le(),
23085                "replace_range should start before or at cursor position"
23086            );
23087
23088            let should_replace = match intent {
23089                CompletionIntent::CompleteWithInsert => false,
23090                CompletionIntent::CompleteWithReplace => true,
23091                CompletionIntent::Complete | CompletionIntent::Compose => {
23092                    let insert_mode =
23093                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23094                            .completions
23095                            .lsp_insert_mode;
23096                    match insert_mode {
23097                        LspInsertMode::Insert => false,
23098                        LspInsertMode::Replace => true,
23099                        LspInsertMode::ReplaceSubsequence => {
23100                            let mut text_to_replace = buffer.chars_for_range(
23101                                buffer.anchor_before(replace_range.start)
23102                                    ..buffer.anchor_after(replace_range.end),
23103                            );
23104                            let mut current_needle = text_to_replace.next();
23105                            for haystack_ch in completion.label.text.chars() {
23106                                if let Some(needle_ch) = current_needle
23107                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23108                                {
23109                                    current_needle = text_to_replace.next();
23110                                }
23111                            }
23112                            current_needle.is_none()
23113                        }
23114                        LspInsertMode::ReplaceSuffix => {
23115                            if replace_range
23116                                .end
23117                                .cmp(cursor_position, &buffer_snapshot)
23118                                .is_gt()
23119                            {
23120                                let range_after_cursor = *cursor_position..replace_range.end;
23121                                let text_after_cursor = buffer
23122                                    .text_for_range(
23123                                        buffer.anchor_before(range_after_cursor.start)
23124                                            ..buffer.anchor_after(range_after_cursor.end),
23125                                    )
23126                                    .collect::<String>()
23127                                    .to_ascii_lowercase();
23128                                completion
23129                                    .label
23130                                    .text
23131                                    .to_ascii_lowercase()
23132                                    .ends_with(&text_after_cursor)
23133                            } else {
23134                                true
23135                            }
23136                        }
23137                    }
23138                }
23139            };
23140
23141            if should_replace {
23142                replace_range.clone()
23143            } else {
23144                insert_range.clone()
23145            }
23146        } else {
23147            replace_range.clone()
23148        }
23149    };
23150
23151    if range_to_replace
23152        .end
23153        .cmp(cursor_position, &buffer_snapshot)
23154        .is_lt()
23155    {
23156        range_to_replace.end = *cursor_position;
23157    }
23158
23159    let replace_range = range_to_replace.to_offset(buffer);
23160    CompletionEdit {
23161        new_text,
23162        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23163        snippet,
23164    }
23165}
23166
23167struct CompletionEdit {
23168    new_text: String,
23169    replace_range: Range<BufferOffset>,
23170    snippet: Option<Snippet>,
23171}
23172
23173fn insert_extra_newline_brackets(
23174    buffer: &MultiBufferSnapshot,
23175    range: Range<MultiBufferOffset>,
23176    language: &language::LanguageScope,
23177) -> bool {
23178    let leading_whitespace_len = buffer
23179        .reversed_chars_at(range.start)
23180        .take_while(|c| c.is_whitespace() && *c != '\n')
23181        .map(|c| c.len_utf8())
23182        .sum::<usize>();
23183    let trailing_whitespace_len = buffer
23184        .chars_at(range.end)
23185        .take_while(|c| c.is_whitespace() && *c != '\n')
23186        .map(|c| c.len_utf8())
23187        .sum::<usize>();
23188    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23189
23190    language.brackets().any(|(pair, enabled)| {
23191        let pair_start = pair.start.trim_end();
23192        let pair_end = pair.end.trim_start();
23193
23194        enabled
23195            && pair.newline
23196            && buffer.contains_str_at(range.end, pair_end)
23197            && buffer.contains_str_at(
23198                range.start.saturating_sub_usize(pair_start.len()),
23199                pair_start,
23200            )
23201    })
23202}
23203
23204fn insert_extra_newline_tree_sitter(
23205    buffer: &MultiBufferSnapshot,
23206    range: Range<MultiBufferOffset>,
23207) -> bool {
23208    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23209        [(buffer, range, _)] => (*buffer, range.clone()),
23210        _ => return false,
23211    };
23212    let pair = {
23213        let mut result: Option<BracketMatch<usize>> = None;
23214
23215        for pair in buffer
23216            .all_bracket_ranges(range.start.0..range.end.0)
23217            .filter(move |pair| {
23218                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23219            })
23220        {
23221            let len = pair.close_range.end - pair.open_range.start;
23222
23223            if let Some(existing) = &result {
23224                let existing_len = existing.close_range.end - existing.open_range.start;
23225                if len > existing_len {
23226                    continue;
23227                }
23228            }
23229
23230            result = Some(pair);
23231        }
23232
23233        result
23234    };
23235    let Some(pair) = pair else {
23236        return false;
23237    };
23238    pair.newline_only
23239        && buffer
23240            .chars_for_range(pair.open_range.end..range.start.0)
23241            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23242            .all(|c| c.is_whitespace() && c != '\n')
23243}
23244
23245fn update_uncommitted_diff_for_buffer(
23246    editor: Entity<Editor>,
23247    project: &Entity<Project>,
23248    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23249    buffer: Entity<MultiBuffer>,
23250    cx: &mut App,
23251) -> Task<()> {
23252    let mut tasks = Vec::new();
23253    project.update(cx, |project, cx| {
23254        for buffer in buffers {
23255            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23256                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23257            }
23258        }
23259    });
23260    cx.spawn(async move |cx| {
23261        let diffs = future::join_all(tasks).await;
23262        if editor
23263            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23264            .unwrap_or(false)
23265        {
23266            return;
23267        }
23268
23269        buffer
23270            .update(cx, |buffer, cx| {
23271                for diff in diffs.into_iter().flatten() {
23272                    buffer.add_diff(diff, cx);
23273                }
23274            })
23275            .ok();
23276    })
23277}
23278
23279fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23280    let tab_size = tab_size.get() as usize;
23281    let mut width = offset;
23282
23283    for ch in text.chars() {
23284        width += if ch == '\t' {
23285            tab_size - (width % tab_size)
23286        } else {
23287            1
23288        };
23289    }
23290
23291    width - offset
23292}
23293
23294#[cfg(test)]
23295mod tests {
23296    use super::*;
23297
23298    #[test]
23299    fn test_string_size_with_expanded_tabs() {
23300        let nz = |val| NonZeroU32::new(val).unwrap();
23301        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23302        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23303        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23304        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23305        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23306        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23307        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23308        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23309    }
23310}
23311
23312/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23313struct WordBreakingTokenizer<'a> {
23314    input: &'a str,
23315}
23316
23317impl<'a> WordBreakingTokenizer<'a> {
23318    fn new(input: &'a str) -> Self {
23319        Self { input }
23320    }
23321}
23322
23323fn is_char_ideographic(ch: char) -> bool {
23324    use unicode_script::Script::*;
23325    use unicode_script::UnicodeScript;
23326    matches!(ch.script(), Han | Tangut | Yi)
23327}
23328
23329fn is_grapheme_ideographic(text: &str) -> bool {
23330    text.chars().any(is_char_ideographic)
23331}
23332
23333fn is_grapheme_whitespace(text: &str) -> bool {
23334    text.chars().any(|x| x.is_whitespace())
23335}
23336
23337fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23338    text.chars()
23339        .next()
23340        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23341}
23342
23343#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23344enum WordBreakToken<'a> {
23345    Word { token: &'a str, grapheme_len: usize },
23346    InlineWhitespace { token: &'a str, grapheme_len: usize },
23347    Newline,
23348}
23349
23350impl<'a> Iterator for WordBreakingTokenizer<'a> {
23351    /// Yields a span, the count of graphemes in the token, and whether it was
23352    /// whitespace. Note that it also breaks at word boundaries.
23353    type Item = WordBreakToken<'a>;
23354
23355    fn next(&mut self) -> Option<Self::Item> {
23356        use unicode_segmentation::UnicodeSegmentation;
23357        if self.input.is_empty() {
23358            return None;
23359        }
23360
23361        let mut iter = self.input.graphemes(true).peekable();
23362        let mut offset = 0;
23363        let mut grapheme_len = 0;
23364        if let Some(first_grapheme) = iter.next() {
23365            let is_newline = first_grapheme == "\n";
23366            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23367            offset += first_grapheme.len();
23368            grapheme_len += 1;
23369            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23370                if let Some(grapheme) = iter.peek().copied()
23371                    && should_stay_with_preceding_ideograph(grapheme)
23372                {
23373                    offset += grapheme.len();
23374                    grapheme_len += 1;
23375                }
23376            } else {
23377                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23378                let mut next_word_bound = words.peek().copied();
23379                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23380                    next_word_bound = words.next();
23381                }
23382                while let Some(grapheme) = iter.peek().copied() {
23383                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23384                        break;
23385                    };
23386                    if is_grapheme_whitespace(grapheme) != is_whitespace
23387                        || (grapheme == "\n") != is_newline
23388                    {
23389                        break;
23390                    };
23391                    offset += grapheme.len();
23392                    grapheme_len += 1;
23393                    iter.next();
23394                }
23395            }
23396            let token = &self.input[..offset];
23397            self.input = &self.input[offset..];
23398            if token == "\n" {
23399                Some(WordBreakToken::Newline)
23400            } else if is_whitespace {
23401                Some(WordBreakToken::InlineWhitespace {
23402                    token,
23403                    grapheme_len,
23404                })
23405            } else {
23406                Some(WordBreakToken::Word {
23407                    token,
23408                    grapheme_len,
23409                })
23410            }
23411        } else {
23412            None
23413        }
23414    }
23415}
23416
23417#[test]
23418fn test_word_breaking_tokenizer() {
23419    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23420        ("", &[]),
23421        ("  ", &[whitespace("  ", 2)]),
23422        ("Ʒ", &[word("Ʒ", 1)]),
23423        ("Ǽ", &[word("Ǽ", 1)]),
23424        ("", &[word("", 1)]),
23425        ("⋑⋑", &[word("⋑⋑", 2)]),
23426        (
23427            "原理,进而",
23428            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23429        ),
23430        (
23431            "hello world",
23432            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23433        ),
23434        (
23435            "hello, world",
23436            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23437        ),
23438        (
23439            "  hello world",
23440            &[
23441                whitespace("  ", 2),
23442                word("hello", 5),
23443                whitespace(" ", 1),
23444                word("world", 5),
23445            ],
23446        ),
23447        (
23448            "这是什么 \n 钢笔",
23449            &[
23450                word("", 1),
23451                word("", 1),
23452                word("", 1),
23453                word("", 1),
23454                whitespace(" ", 1),
23455                newline(),
23456                whitespace(" ", 1),
23457                word("", 1),
23458                word("", 1),
23459            ],
23460        ),
23461        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23462    ];
23463
23464    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23465        WordBreakToken::Word {
23466            token,
23467            grapheme_len,
23468        }
23469    }
23470
23471    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23472        WordBreakToken::InlineWhitespace {
23473            token,
23474            grapheme_len,
23475        }
23476    }
23477
23478    fn newline() -> WordBreakToken<'static> {
23479        WordBreakToken::Newline
23480    }
23481
23482    for (input, result) in tests {
23483        assert_eq!(
23484            WordBreakingTokenizer::new(input)
23485                .collect::<Vec<_>>()
23486                .as_slice(),
23487            *result,
23488        );
23489    }
23490}
23491
23492fn wrap_with_prefix(
23493    first_line_prefix: String,
23494    subsequent_lines_prefix: String,
23495    unwrapped_text: String,
23496    wrap_column: usize,
23497    tab_size: NonZeroU32,
23498    preserve_existing_whitespace: bool,
23499) -> String {
23500    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23501    let subsequent_lines_prefix_len =
23502        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23503    let mut wrapped_text = String::new();
23504    let mut current_line = first_line_prefix;
23505    let mut is_first_line = true;
23506
23507    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23508    let mut current_line_len = first_line_prefix_len;
23509    let mut in_whitespace = false;
23510    for token in tokenizer {
23511        let have_preceding_whitespace = in_whitespace;
23512        match token {
23513            WordBreakToken::Word {
23514                token,
23515                grapheme_len,
23516            } => {
23517                in_whitespace = false;
23518                let current_prefix_len = if is_first_line {
23519                    first_line_prefix_len
23520                } else {
23521                    subsequent_lines_prefix_len
23522                };
23523                if current_line_len + grapheme_len > wrap_column
23524                    && current_line_len != current_prefix_len
23525                {
23526                    wrapped_text.push_str(current_line.trim_end());
23527                    wrapped_text.push('\n');
23528                    is_first_line = false;
23529                    current_line = subsequent_lines_prefix.clone();
23530                    current_line_len = subsequent_lines_prefix_len;
23531                }
23532                current_line.push_str(token);
23533                current_line_len += grapheme_len;
23534            }
23535            WordBreakToken::InlineWhitespace {
23536                mut token,
23537                mut grapheme_len,
23538            } => {
23539                in_whitespace = true;
23540                if have_preceding_whitespace && !preserve_existing_whitespace {
23541                    continue;
23542                }
23543                if !preserve_existing_whitespace {
23544                    // Keep a single whitespace grapheme as-is
23545                    if let Some(first) =
23546                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23547                    {
23548                        token = first;
23549                    } else {
23550                        token = " ";
23551                    }
23552                    grapheme_len = 1;
23553                }
23554                let current_prefix_len = if is_first_line {
23555                    first_line_prefix_len
23556                } else {
23557                    subsequent_lines_prefix_len
23558                };
23559                if current_line_len + grapheme_len > wrap_column {
23560                    wrapped_text.push_str(current_line.trim_end());
23561                    wrapped_text.push('\n');
23562                    is_first_line = false;
23563                    current_line = subsequent_lines_prefix.clone();
23564                    current_line_len = subsequent_lines_prefix_len;
23565                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23566                    current_line.push_str(token);
23567                    current_line_len += grapheme_len;
23568                }
23569            }
23570            WordBreakToken::Newline => {
23571                in_whitespace = true;
23572                let current_prefix_len = if is_first_line {
23573                    first_line_prefix_len
23574                } else {
23575                    subsequent_lines_prefix_len
23576                };
23577                if preserve_existing_whitespace {
23578                    wrapped_text.push_str(current_line.trim_end());
23579                    wrapped_text.push('\n');
23580                    is_first_line = false;
23581                    current_line = subsequent_lines_prefix.clone();
23582                    current_line_len = subsequent_lines_prefix_len;
23583                } else if have_preceding_whitespace {
23584                    continue;
23585                } else if current_line_len + 1 > wrap_column
23586                    && current_line_len != current_prefix_len
23587                {
23588                    wrapped_text.push_str(current_line.trim_end());
23589                    wrapped_text.push('\n');
23590                    is_first_line = false;
23591                    current_line = subsequent_lines_prefix.clone();
23592                    current_line_len = subsequent_lines_prefix_len;
23593                } else if current_line_len != current_prefix_len {
23594                    current_line.push(' ');
23595                    current_line_len += 1;
23596                }
23597            }
23598        }
23599    }
23600
23601    if !current_line.is_empty() {
23602        wrapped_text.push_str(&current_line);
23603    }
23604    wrapped_text
23605}
23606
23607#[test]
23608fn test_wrap_with_prefix() {
23609    assert_eq!(
23610        wrap_with_prefix(
23611            "# ".to_string(),
23612            "# ".to_string(),
23613            "abcdefg".to_string(),
23614            4,
23615            NonZeroU32::new(4).unwrap(),
23616            false,
23617        ),
23618        "# abcdefg"
23619    );
23620    assert_eq!(
23621        wrap_with_prefix(
23622            "".to_string(),
23623            "".to_string(),
23624            "\thello world".to_string(),
23625            8,
23626            NonZeroU32::new(4).unwrap(),
23627            false,
23628        ),
23629        "hello\nworld"
23630    );
23631    assert_eq!(
23632        wrap_with_prefix(
23633            "// ".to_string(),
23634            "// ".to_string(),
23635            "xx \nyy zz aa bb cc".to_string(),
23636            12,
23637            NonZeroU32::new(4).unwrap(),
23638            false,
23639        ),
23640        "// xx yy zz\n// aa bb cc"
23641    );
23642    assert_eq!(
23643        wrap_with_prefix(
23644            String::new(),
23645            String::new(),
23646            "这是什么 \n 钢笔".to_string(),
23647            3,
23648            NonZeroU32::new(4).unwrap(),
23649            false,
23650        ),
23651        "这是什\n么 钢\n"
23652    );
23653    assert_eq!(
23654        wrap_with_prefix(
23655            String::new(),
23656            String::new(),
23657            format!("foo{}bar", '\u{2009}'), // thin space
23658            80,
23659            NonZeroU32::new(4).unwrap(),
23660            false,
23661        ),
23662        format!("foo{}bar", '\u{2009}')
23663    );
23664}
23665
23666pub trait CollaborationHub {
23667    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23668    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23669    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23670}
23671
23672impl CollaborationHub for Entity<Project> {
23673    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23674        self.read(cx).collaborators()
23675    }
23676
23677    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23678        self.read(cx).user_store().read(cx).participant_indices()
23679    }
23680
23681    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23682        let this = self.read(cx);
23683        let user_ids = this.collaborators().values().map(|c| c.user_id);
23684        this.user_store().read(cx).participant_names(user_ids, cx)
23685    }
23686}
23687
23688pub trait SemanticsProvider {
23689    fn hover(
23690        &self,
23691        buffer: &Entity<Buffer>,
23692        position: text::Anchor,
23693        cx: &mut App,
23694    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23695
23696    fn inline_values(
23697        &self,
23698        buffer_handle: Entity<Buffer>,
23699        range: Range<text::Anchor>,
23700        cx: &mut App,
23701    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23702
23703    fn applicable_inlay_chunks(
23704        &self,
23705        buffer: &Entity<Buffer>,
23706        ranges: &[Range<text::Anchor>],
23707        cx: &mut App,
23708    ) -> Vec<Range<BufferRow>>;
23709
23710    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23711
23712    fn inlay_hints(
23713        &self,
23714        invalidate: InvalidationStrategy,
23715        buffer: Entity<Buffer>,
23716        ranges: Vec<Range<text::Anchor>>,
23717        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23718        cx: &mut App,
23719    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23720
23721    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23722
23723    fn document_highlights(
23724        &self,
23725        buffer: &Entity<Buffer>,
23726        position: text::Anchor,
23727        cx: &mut App,
23728    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23729
23730    fn definitions(
23731        &self,
23732        buffer: &Entity<Buffer>,
23733        position: text::Anchor,
23734        kind: GotoDefinitionKind,
23735        cx: &mut App,
23736    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23737
23738    fn range_for_rename(
23739        &self,
23740        buffer: &Entity<Buffer>,
23741        position: text::Anchor,
23742        cx: &mut App,
23743    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23744
23745    fn perform_rename(
23746        &self,
23747        buffer: &Entity<Buffer>,
23748        position: text::Anchor,
23749        new_name: String,
23750        cx: &mut App,
23751    ) -> Option<Task<Result<ProjectTransaction>>>;
23752}
23753
23754pub trait CompletionProvider {
23755    fn completions(
23756        &self,
23757        excerpt_id: ExcerptId,
23758        buffer: &Entity<Buffer>,
23759        buffer_position: text::Anchor,
23760        trigger: CompletionContext,
23761        window: &mut Window,
23762        cx: &mut Context<Editor>,
23763    ) -> Task<Result<Vec<CompletionResponse>>>;
23764
23765    fn resolve_completions(
23766        &self,
23767        _buffer: Entity<Buffer>,
23768        _completion_indices: Vec<usize>,
23769        _completions: Rc<RefCell<Box<[Completion]>>>,
23770        _cx: &mut Context<Editor>,
23771    ) -> Task<Result<bool>> {
23772        Task::ready(Ok(false))
23773    }
23774
23775    fn apply_additional_edits_for_completion(
23776        &self,
23777        _buffer: Entity<Buffer>,
23778        _completions: Rc<RefCell<Box<[Completion]>>>,
23779        _completion_index: usize,
23780        _push_to_history: bool,
23781        _cx: &mut Context<Editor>,
23782    ) -> Task<Result<Option<language::Transaction>>> {
23783        Task::ready(Ok(None))
23784    }
23785
23786    fn is_completion_trigger(
23787        &self,
23788        buffer: &Entity<Buffer>,
23789        position: language::Anchor,
23790        text: &str,
23791        trigger_in_words: bool,
23792        cx: &mut Context<Editor>,
23793    ) -> bool;
23794
23795    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23796
23797    fn sort_completions(&self) -> bool {
23798        true
23799    }
23800
23801    fn filter_completions(&self) -> bool {
23802        true
23803    }
23804
23805    fn show_snippets(&self) -> bool {
23806        false
23807    }
23808}
23809
23810pub trait CodeActionProvider {
23811    fn id(&self) -> Arc<str>;
23812
23813    fn code_actions(
23814        &self,
23815        buffer: &Entity<Buffer>,
23816        range: Range<text::Anchor>,
23817        window: &mut Window,
23818        cx: &mut App,
23819    ) -> Task<Result<Vec<CodeAction>>>;
23820
23821    fn apply_code_action(
23822        &self,
23823        buffer_handle: Entity<Buffer>,
23824        action: CodeAction,
23825        excerpt_id: ExcerptId,
23826        push_to_history: bool,
23827        window: &mut Window,
23828        cx: &mut App,
23829    ) -> Task<Result<ProjectTransaction>>;
23830}
23831
23832impl CodeActionProvider for Entity<Project> {
23833    fn id(&self) -> Arc<str> {
23834        "project".into()
23835    }
23836
23837    fn code_actions(
23838        &self,
23839        buffer: &Entity<Buffer>,
23840        range: Range<text::Anchor>,
23841        _window: &mut Window,
23842        cx: &mut App,
23843    ) -> Task<Result<Vec<CodeAction>>> {
23844        self.update(cx, |project, cx| {
23845            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23846            let code_actions = project.code_actions(buffer, range, None, cx);
23847            cx.background_spawn(async move {
23848                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23849                Ok(code_lens_actions
23850                    .context("code lens fetch")?
23851                    .into_iter()
23852                    .flatten()
23853                    .chain(
23854                        code_actions
23855                            .context("code action fetch")?
23856                            .into_iter()
23857                            .flatten(),
23858                    )
23859                    .collect())
23860            })
23861        })
23862    }
23863
23864    fn apply_code_action(
23865        &self,
23866        buffer_handle: Entity<Buffer>,
23867        action: CodeAction,
23868        _excerpt_id: ExcerptId,
23869        push_to_history: bool,
23870        _window: &mut Window,
23871        cx: &mut App,
23872    ) -> Task<Result<ProjectTransaction>> {
23873        self.update(cx, |project, cx| {
23874            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23875        })
23876    }
23877}
23878
23879fn snippet_completions(
23880    project: &Project,
23881    buffer: &Entity<Buffer>,
23882    buffer_anchor: text::Anchor,
23883    classifier: CharClassifier,
23884    cx: &mut App,
23885) -> Task<Result<CompletionResponse>> {
23886    let languages = buffer.read(cx).languages_at(buffer_anchor);
23887    let snippet_store = project.snippets().read(cx);
23888
23889    let scopes: Vec<_> = languages
23890        .iter()
23891        .filter_map(|language| {
23892            let language_name = language.lsp_id();
23893            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23894
23895            if snippets.is_empty() {
23896                None
23897            } else {
23898                Some((language.default_scope(), snippets))
23899            }
23900        })
23901        .collect();
23902
23903    if scopes.is_empty() {
23904        return Task::ready(Ok(CompletionResponse {
23905            completions: vec![],
23906            display_options: CompletionDisplayOptions::default(),
23907            is_incomplete: false,
23908        }));
23909    }
23910
23911    let snapshot = buffer.read(cx).text_snapshot();
23912    let executor = cx.background_executor().clone();
23913
23914    cx.background_spawn(async move {
23915        let is_word_char = |c| classifier.is_word(c);
23916
23917        let mut is_incomplete = false;
23918        let mut completions: Vec<Completion> = Vec::new();
23919
23920        const MAX_PREFIX_LEN: usize = 128;
23921        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23922        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23923        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23924
23925        let max_buffer_window: String = snapshot
23926            .text_for_range(window_start..buffer_offset)
23927            .collect();
23928
23929        if max_buffer_window.is_empty() {
23930            return Ok(CompletionResponse {
23931                completions: vec![],
23932                display_options: CompletionDisplayOptions::default(),
23933                is_incomplete: true,
23934            });
23935        }
23936
23937        for (_scope, snippets) in scopes.into_iter() {
23938            // Sort snippets by word count to match longer snippet prefixes first.
23939            let mut sorted_snippet_candidates = snippets
23940                .iter()
23941                .enumerate()
23942                .flat_map(|(snippet_ix, snippet)| {
23943                    snippet
23944                        .prefix
23945                        .iter()
23946                        .enumerate()
23947                        .map(move |(prefix_ix, prefix)| {
23948                            let word_count =
23949                                snippet_candidate_suffixes(prefix, is_word_char).count();
23950                            ((snippet_ix, prefix_ix), prefix, word_count)
23951                        })
23952                })
23953                .collect_vec();
23954            sorted_snippet_candidates
23955                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23956
23957            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23958
23959            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23960                .take(
23961                    sorted_snippet_candidates
23962                        .first()
23963                        .map(|(_, _, word_count)| *word_count)
23964                        .unwrap_or_default(),
23965                )
23966                .collect_vec();
23967
23968            const MAX_RESULTS: usize = 100;
23969            // Each match also remembers how many characters from the buffer it consumed
23970            let mut matches: Vec<(StringMatch, usize)> = vec![];
23971
23972            let mut snippet_list_cutoff_index = 0;
23973            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23974                let word_count = buffer_index + 1;
23975                // Increase `snippet_list_cutoff_index` until we have all of the
23976                // snippets with sufficiently many words.
23977                while sorted_snippet_candidates
23978                    .get(snippet_list_cutoff_index)
23979                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23980                        *snippet_word_count >= word_count
23981                    })
23982                {
23983                    snippet_list_cutoff_index += 1;
23984                }
23985
23986                // Take only the candidates with at least `word_count` many words
23987                let snippet_candidates_at_word_len =
23988                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23989
23990                let candidates = snippet_candidates_at_word_len
23991                    .iter()
23992                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23993                    .enumerate() // index in `sorted_snippet_candidates`
23994                    // First char must match
23995                    .filter(|(_ix, prefix)| {
23996                        itertools::equal(
23997                            prefix
23998                                .chars()
23999                                .next()
24000                                .into_iter()
24001                                .flat_map(|c| c.to_lowercase()),
24002                            buffer_window
24003                                .chars()
24004                                .next()
24005                                .into_iter()
24006                                .flat_map(|c| c.to_lowercase()),
24007                        )
24008                    })
24009                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24010                    .collect::<Vec<StringMatchCandidate>>();
24011
24012                matches.extend(
24013                    fuzzy::match_strings(
24014                        &candidates,
24015                        &buffer_window,
24016                        buffer_window.chars().any(|c| c.is_uppercase()),
24017                        true,
24018                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24019                        &Default::default(),
24020                        executor.clone(),
24021                    )
24022                    .await
24023                    .into_iter()
24024                    .map(|string_match| (string_match, buffer_window.len())),
24025                );
24026
24027                if matches.len() >= MAX_RESULTS {
24028                    break;
24029                }
24030            }
24031
24032            let to_lsp = |point: &text::Anchor| {
24033                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24034                point_to_lsp(end)
24035            };
24036            let lsp_end = to_lsp(&buffer_anchor);
24037
24038            if matches.len() >= MAX_RESULTS {
24039                is_incomplete = true;
24040            }
24041
24042            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24043                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24044                    sorted_snippet_candidates[string_match.candidate_id];
24045                let snippet = &snippets[snippet_index];
24046                let start = buffer_offset - buffer_window_len;
24047                let start = snapshot.anchor_before(start);
24048                let range = start..buffer_anchor;
24049                let lsp_start = to_lsp(&start);
24050                let lsp_range = lsp::Range {
24051                    start: lsp_start,
24052                    end: lsp_end,
24053                };
24054                Completion {
24055                    replace_range: range,
24056                    new_text: snippet.body.clone(),
24057                    source: CompletionSource::Lsp {
24058                        insert_range: None,
24059                        server_id: LanguageServerId(usize::MAX),
24060                        resolved: true,
24061                        lsp_completion: Box::new(lsp::CompletionItem {
24062                            label: snippet.prefix.first().unwrap().clone(),
24063                            kind: Some(CompletionItemKind::SNIPPET),
24064                            label_details: snippet.description.as_ref().map(|description| {
24065                                lsp::CompletionItemLabelDetails {
24066                                    detail: Some(description.clone()),
24067                                    description: None,
24068                                }
24069                            }),
24070                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24071                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24072                                lsp::InsertReplaceEdit {
24073                                    new_text: snippet.body.clone(),
24074                                    insert: lsp_range,
24075                                    replace: lsp_range,
24076                                },
24077                            )),
24078                            filter_text: Some(snippet.body.clone()),
24079                            sort_text: Some(char::MAX.to_string()),
24080                            ..lsp::CompletionItem::default()
24081                        }),
24082                        lsp_defaults: None,
24083                    },
24084                    label: CodeLabel {
24085                        text: matching_prefix.clone(),
24086                        runs: Vec::new(),
24087                        filter_range: 0..matching_prefix.len(),
24088                    },
24089                    icon_path: None,
24090                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24091                        single_line: snippet.name.clone().into(),
24092                        plain_text: snippet
24093                            .description
24094                            .clone()
24095                            .map(|description| description.into()),
24096                    }),
24097                    insert_text_mode: None,
24098                    confirm: None,
24099                    match_start: Some(start),
24100                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24101                }
24102            }));
24103        }
24104
24105        Ok(CompletionResponse {
24106            completions,
24107            display_options: CompletionDisplayOptions::default(),
24108            is_incomplete,
24109        })
24110    })
24111}
24112
24113impl CompletionProvider for Entity<Project> {
24114    fn completions(
24115        &self,
24116        _excerpt_id: ExcerptId,
24117        buffer: &Entity<Buffer>,
24118        buffer_position: text::Anchor,
24119        options: CompletionContext,
24120        _window: &mut Window,
24121        cx: &mut Context<Editor>,
24122    ) -> Task<Result<Vec<CompletionResponse>>> {
24123        self.update(cx, |project, cx| {
24124            let task = project.completions(buffer, buffer_position, options, cx);
24125            cx.background_spawn(task)
24126        })
24127    }
24128
24129    fn resolve_completions(
24130        &self,
24131        buffer: Entity<Buffer>,
24132        completion_indices: Vec<usize>,
24133        completions: Rc<RefCell<Box<[Completion]>>>,
24134        cx: &mut Context<Editor>,
24135    ) -> Task<Result<bool>> {
24136        self.update(cx, |project, cx| {
24137            project.lsp_store().update(cx, |lsp_store, cx| {
24138                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24139            })
24140        })
24141    }
24142
24143    fn apply_additional_edits_for_completion(
24144        &self,
24145        buffer: Entity<Buffer>,
24146        completions: Rc<RefCell<Box<[Completion]>>>,
24147        completion_index: usize,
24148        push_to_history: bool,
24149        cx: &mut Context<Editor>,
24150    ) -> Task<Result<Option<language::Transaction>>> {
24151        self.update(cx, |project, cx| {
24152            project.lsp_store().update(cx, |lsp_store, cx| {
24153                lsp_store.apply_additional_edits_for_completion(
24154                    buffer,
24155                    completions,
24156                    completion_index,
24157                    push_to_history,
24158                    cx,
24159                )
24160            })
24161        })
24162    }
24163
24164    fn is_completion_trigger(
24165        &self,
24166        buffer: &Entity<Buffer>,
24167        position: language::Anchor,
24168        text: &str,
24169        trigger_in_words: bool,
24170        cx: &mut Context<Editor>,
24171    ) -> bool {
24172        let mut chars = text.chars();
24173        let char = if let Some(char) = chars.next() {
24174            char
24175        } else {
24176            return false;
24177        };
24178        if chars.next().is_some() {
24179            return false;
24180        }
24181
24182        let buffer = buffer.read(cx);
24183        let snapshot = buffer.snapshot();
24184        let classifier = snapshot
24185            .char_classifier_at(position)
24186            .scope_context(Some(CharScopeContext::Completion));
24187        if trigger_in_words && classifier.is_word(char) {
24188            return true;
24189        }
24190
24191        buffer.completion_triggers().contains(text)
24192    }
24193
24194    fn show_snippets(&self) -> bool {
24195        true
24196    }
24197}
24198
24199impl SemanticsProvider for Entity<Project> {
24200    fn hover(
24201        &self,
24202        buffer: &Entity<Buffer>,
24203        position: text::Anchor,
24204        cx: &mut App,
24205    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24206        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24207    }
24208
24209    fn document_highlights(
24210        &self,
24211        buffer: &Entity<Buffer>,
24212        position: text::Anchor,
24213        cx: &mut App,
24214    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24215        Some(self.update(cx, |project, cx| {
24216            project.document_highlights(buffer, position, cx)
24217        }))
24218    }
24219
24220    fn definitions(
24221        &self,
24222        buffer: &Entity<Buffer>,
24223        position: text::Anchor,
24224        kind: GotoDefinitionKind,
24225        cx: &mut App,
24226    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24227        Some(self.update(cx, |project, cx| match kind {
24228            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24229            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24230            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24231            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24232        }))
24233    }
24234
24235    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24236        self.update(cx, |project, cx| {
24237            if project
24238                .active_debug_session(cx)
24239                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24240            {
24241                return true;
24242            }
24243
24244            buffer.update(cx, |buffer, cx| {
24245                project.any_language_server_supports_inlay_hints(buffer, cx)
24246            })
24247        })
24248    }
24249
24250    fn inline_values(
24251        &self,
24252        buffer_handle: Entity<Buffer>,
24253        range: Range<text::Anchor>,
24254        cx: &mut App,
24255    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24256        self.update(cx, |project, cx| {
24257            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24258
24259            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24260        })
24261    }
24262
24263    fn applicable_inlay_chunks(
24264        &self,
24265        buffer: &Entity<Buffer>,
24266        ranges: &[Range<text::Anchor>],
24267        cx: &mut App,
24268    ) -> Vec<Range<BufferRow>> {
24269        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24270            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24271        })
24272    }
24273
24274    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24275        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24276            lsp_store.invalidate_inlay_hints(for_buffers)
24277        });
24278    }
24279
24280    fn inlay_hints(
24281        &self,
24282        invalidate: InvalidationStrategy,
24283        buffer: Entity<Buffer>,
24284        ranges: Vec<Range<text::Anchor>>,
24285        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24286        cx: &mut App,
24287    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24288        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24289            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24290        }))
24291    }
24292
24293    fn range_for_rename(
24294        &self,
24295        buffer: &Entity<Buffer>,
24296        position: text::Anchor,
24297        cx: &mut App,
24298    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24299        Some(self.update(cx, |project, cx| {
24300            let buffer = buffer.clone();
24301            let task = project.prepare_rename(buffer.clone(), position, cx);
24302            cx.spawn(async move |_, cx| {
24303                Ok(match task.await? {
24304                    PrepareRenameResponse::Success(range) => Some(range),
24305                    PrepareRenameResponse::InvalidPosition => None,
24306                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24307                        // Fallback on using TreeSitter info to determine identifier range
24308                        buffer.read_with(cx, |buffer, _| {
24309                            let snapshot = buffer.snapshot();
24310                            let (range, kind) = snapshot.surrounding_word(position, None);
24311                            if kind != Some(CharKind::Word) {
24312                                return None;
24313                            }
24314                            Some(
24315                                snapshot.anchor_before(range.start)
24316                                    ..snapshot.anchor_after(range.end),
24317                            )
24318                        })?
24319                    }
24320                })
24321            })
24322        }))
24323    }
24324
24325    fn perform_rename(
24326        &self,
24327        buffer: &Entity<Buffer>,
24328        position: text::Anchor,
24329        new_name: String,
24330        cx: &mut App,
24331    ) -> Option<Task<Result<ProjectTransaction>>> {
24332        Some(self.update(cx, |project, cx| {
24333            project.perform_rename(buffer.clone(), position, new_name, cx)
24334        }))
24335    }
24336}
24337
24338fn consume_contiguous_rows(
24339    contiguous_row_selections: &mut Vec<Selection<Point>>,
24340    selection: &Selection<Point>,
24341    display_map: &DisplaySnapshot,
24342    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24343) -> (MultiBufferRow, MultiBufferRow) {
24344    contiguous_row_selections.push(selection.clone());
24345    let start_row = starting_row(selection, display_map);
24346    let mut end_row = ending_row(selection, display_map);
24347
24348    while let Some(next_selection) = selections.peek() {
24349        if next_selection.start.row <= end_row.0 {
24350            end_row = ending_row(next_selection, display_map);
24351            contiguous_row_selections.push(selections.next().unwrap().clone());
24352        } else {
24353            break;
24354        }
24355    }
24356    (start_row, end_row)
24357}
24358
24359fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24360    if selection.start.column > 0 {
24361        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24362    } else {
24363        MultiBufferRow(selection.start.row)
24364    }
24365}
24366
24367fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24368    if next_selection.end.column > 0 || next_selection.is_empty() {
24369        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24370    } else {
24371        MultiBufferRow(next_selection.end.row)
24372    }
24373}
24374
24375impl EditorSnapshot {
24376    pub fn remote_selections_in_range<'a>(
24377        &'a self,
24378        range: &'a Range<Anchor>,
24379        collaboration_hub: &dyn CollaborationHub,
24380        cx: &'a App,
24381    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24382        let participant_names = collaboration_hub.user_names(cx);
24383        let participant_indices = collaboration_hub.user_participant_indices(cx);
24384        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24385        let collaborators_by_replica_id = collaborators_by_peer_id
24386            .values()
24387            .map(|collaborator| (collaborator.replica_id, collaborator))
24388            .collect::<HashMap<_, _>>();
24389        self.buffer_snapshot()
24390            .selections_in_range(range, false)
24391            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24392                if replica_id == ReplicaId::AGENT {
24393                    Some(RemoteSelection {
24394                        replica_id,
24395                        selection,
24396                        cursor_shape,
24397                        line_mode,
24398                        collaborator_id: CollaboratorId::Agent,
24399                        user_name: Some("Agent".into()),
24400                        color: cx.theme().players().agent(),
24401                    })
24402                } else {
24403                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24404                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24405                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24406                    Some(RemoteSelection {
24407                        replica_id,
24408                        selection,
24409                        cursor_shape,
24410                        line_mode,
24411                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24412                        user_name,
24413                        color: if let Some(index) = participant_index {
24414                            cx.theme().players().color_for_participant(index.0)
24415                        } else {
24416                            cx.theme().players().absent()
24417                        },
24418                    })
24419                }
24420            })
24421    }
24422
24423    pub fn hunks_for_ranges(
24424        &self,
24425        ranges: impl IntoIterator<Item = Range<Point>>,
24426    ) -> Vec<MultiBufferDiffHunk> {
24427        let mut hunks = Vec::new();
24428        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24429            HashMap::default();
24430        for query_range in ranges {
24431            let query_rows =
24432                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24433            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24434                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24435            ) {
24436                // Include deleted hunks that are adjacent to the query range, because
24437                // otherwise they would be missed.
24438                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24439                if hunk.status().is_deleted() {
24440                    intersects_range |= hunk.row_range.start == query_rows.end;
24441                    intersects_range |= hunk.row_range.end == query_rows.start;
24442                }
24443                if intersects_range {
24444                    if !processed_buffer_rows
24445                        .entry(hunk.buffer_id)
24446                        .or_default()
24447                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24448                    {
24449                        continue;
24450                    }
24451                    hunks.push(hunk);
24452                }
24453            }
24454        }
24455
24456        hunks
24457    }
24458
24459    fn display_diff_hunks_for_rows<'a>(
24460        &'a self,
24461        display_rows: Range<DisplayRow>,
24462        folded_buffers: &'a HashSet<BufferId>,
24463    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24464        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24465        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24466
24467        self.buffer_snapshot()
24468            .diff_hunks_in_range(buffer_start..buffer_end)
24469            .filter_map(|hunk| {
24470                if folded_buffers.contains(&hunk.buffer_id) {
24471                    return None;
24472                }
24473
24474                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24475                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24476
24477                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24478                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24479
24480                let display_hunk = if hunk_display_start.column() != 0 {
24481                    DisplayDiffHunk::Folded {
24482                        display_row: hunk_display_start.row(),
24483                    }
24484                } else {
24485                    let mut end_row = hunk_display_end.row();
24486                    if hunk_display_end.column() > 0 {
24487                        end_row.0 += 1;
24488                    }
24489                    let is_created_file = hunk.is_created_file();
24490
24491                    DisplayDiffHunk::Unfolded {
24492                        status: hunk.status(),
24493                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24494                            ..hunk.diff_base_byte_range.end.0,
24495                        word_diffs: hunk.word_diffs,
24496                        display_row_range: hunk_display_start.row()..end_row,
24497                        multi_buffer_range: Anchor::range_in_buffer(
24498                            hunk.excerpt_id,
24499                            hunk.buffer_range,
24500                        ),
24501                        is_created_file,
24502                    }
24503                };
24504
24505                Some(display_hunk)
24506            })
24507    }
24508
24509    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24510        self.display_snapshot
24511            .buffer_snapshot()
24512            .language_at(position)
24513    }
24514
24515    pub fn is_focused(&self) -> bool {
24516        self.is_focused
24517    }
24518
24519    pub fn placeholder_text(&self) -> Option<String> {
24520        self.placeholder_display_snapshot
24521            .as_ref()
24522            .map(|display_map| display_map.text())
24523    }
24524
24525    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24526        self.scroll_anchor.scroll_position(&self.display_snapshot)
24527    }
24528
24529    fn gutter_dimensions(
24530        &self,
24531        font_id: FontId,
24532        font_size: Pixels,
24533        max_line_number_width: Pixels,
24534        cx: &App,
24535    ) -> Option<GutterDimensions> {
24536        if !self.show_gutter {
24537            return None;
24538        }
24539
24540        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
24541        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
24542
24543        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24544            matches!(
24545                ProjectSettings::get_global(cx).git.git_gutter,
24546                GitGutterSetting::TrackedFiles
24547            )
24548        });
24549        let gutter_settings = EditorSettings::get_global(cx).gutter;
24550        let show_line_numbers = self
24551            .show_line_numbers
24552            .unwrap_or(gutter_settings.line_numbers);
24553        let line_gutter_width = if show_line_numbers {
24554            // Avoid flicker-like gutter resizes when the line number gains another digit by
24555            // only resizing the gutter on files with > 10**min_line_number_digits lines.
24556            let min_width_for_number_on_gutter =
24557                ch_advance * gutter_settings.min_line_number_digits as f32;
24558            max_line_number_width.max(min_width_for_number_on_gutter)
24559        } else {
24560            0.0.into()
24561        };
24562
24563        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24564        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24565
24566        let git_blame_entries_width =
24567            self.git_blame_gutter_max_author_length
24568                .map(|max_author_length| {
24569                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24570                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24571
24572                    /// The number of characters to dedicate to gaps and margins.
24573                    const SPACING_WIDTH: usize = 4;
24574
24575                    let max_char_count = max_author_length.min(renderer.max_author_length())
24576                        + ::git::SHORT_SHA_LENGTH
24577                        + MAX_RELATIVE_TIMESTAMP.len()
24578                        + SPACING_WIDTH;
24579
24580                    ch_advance * max_char_count
24581                });
24582
24583        let is_singleton = self.buffer_snapshot().is_singleton();
24584
24585        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24586        left_padding += if !is_singleton {
24587            ch_width * 4.0
24588        } else if show_runnables || show_breakpoints {
24589            ch_width * 3.0
24590        } else if show_git_gutter && show_line_numbers {
24591            ch_width * 2.0
24592        } else if show_git_gutter || show_line_numbers {
24593            ch_width
24594        } else {
24595            px(0.)
24596        };
24597
24598        let shows_folds = is_singleton && gutter_settings.folds;
24599
24600        let right_padding = if shows_folds && show_line_numbers {
24601            ch_width * 4.0
24602        } else if shows_folds || (!is_singleton && show_line_numbers) {
24603            ch_width * 3.0
24604        } else if show_line_numbers {
24605            ch_width
24606        } else {
24607            px(0.)
24608        };
24609
24610        Some(GutterDimensions {
24611            left_padding,
24612            right_padding,
24613            width: line_gutter_width + left_padding + right_padding,
24614            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24615            git_blame_entries_width,
24616        })
24617    }
24618
24619    pub fn render_crease_toggle(
24620        &self,
24621        buffer_row: MultiBufferRow,
24622        row_contains_cursor: bool,
24623        editor: Entity<Editor>,
24624        window: &mut Window,
24625        cx: &mut App,
24626    ) -> Option<AnyElement> {
24627        let folded = self.is_line_folded(buffer_row);
24628        let mut is_foldable = false;
24629
24630        if let Some(crease) = self
24631            .crease_snapshot
24632            .query_row(buffer_row, self.buffer_snapshot())
24633        {
24634            is_foldable = true;
24635            match crease {
24636                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24637                    if let Some(render_toggle) = render_toggle {
24638                        let toggle_callback =
24639                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24640                                if folded {
24641                                    editor.update(cx, |editor, cx| {
24642                                        editor.fold_at(buffer_row, window, cx)
24643                                    });
24644                                } else {
24645                                    editor.update(cx, |editor, cx| {
24646                                        editor.unfold_at(buffer_row, window, cx)
24647                                    });
24648                                }
24649                            });
24650                        return Some((render_toggle)(
24651                            buffer_row,
24652                            folded,
24653                            toggle_callback,
24654                            window,
24655                            cx,
24656                        ));
24657                    }
24658                }
24659            }
24660        }
24661
24662        is_foldable |= self.starts_indent(buffer_row);
24663
24664        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24665            Some(
24666                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24667                    .toggle_state(folded)
24668                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24669                        if folded {
24670                            this.unfold_at(buffer_row, window, cx);
24671                        } else {
24672                            this.fold_at(buffer_row, window, cx);
24673                        }
24674                    }))
24675                    .into_any_element(),
24676            )
24677        } else {
24678            None
24679        }
24680    }
24681
24682    pub fn render_crease_trailer(
24683        &self,
24684        buffer_row: MultiBufferRow,
24685        window: &mut Window,
24686        cx: &mut App,
24687    ) -> Option<AnyElement> {
24688        let folded = self.is_line_folded(buffer_row);
24689        if let Crease::Inline { render_trailer, .. } = self
24690            .crease_snapshot
24691            .query_row(buffer_row, self.buffer_snapshot())?
24692        {
24693            let render_trailer = render_trailer.as_ref()?;
24694            Some(render_trailer(buffer_row, folded, window, cx))
24695        } else {
24696            None
24697        }
24698    }
24699}
24700
24701impl Deref for EditorSnapshot {
24702    type Target = DisplaySnapshot;
24703
24704    fn deref(&self) -> &Self::Target {
24705        &self.display_snapshot
24706    }
24707}
24708
24709#[derive(Clone, Debug, PartialEq, Eq)]
24710pub enum EditorEvent {
24711    InputIgnored {
24712        text: Arc<str>,
24713    },
24714    InputHandled {
24715        utf16_range_to_replace: Option<Range<isize>>,
24716        text: Arc<str>,
24717    },
24718    ExcerptsAdded {
24719        buffer: Entity<Buffer>,
24720        predecessor: ExcerptId,
24721        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24722    },
24723    ExcerptsRemoved {
24724        ids: Vec<ExcerptId>,
24725        removed_buffer_ids: Vec<BufferId>,
24726    },
24727    BufferFoldToggled {
24728        ids: Vec<ExcerptId>,
24729        folded: bool,
24730    },
24731    ExcerptsEdited {
24732        ids: Vec<ExcerptId>,
24733    },
24734    ExcerptsExpanded {
24735        ids: Vec<ExcerptId>,
24736    },
24737    BufferEdited,
24738    Edited {
24739        transaction_id: clock::Lamport,
24740    },
24741    Reparsed(BufferId),
24742    Focused,
24743    FocusedIn,
24744    Blurred,
24745    DirtyChanged,
24746    Saved,
24747    TitleChanged,
24748    SelectionsChanged {
24749        local: bool,
24750    },
24751    ScrollPositionChanged {
24752        local: bool,
24753        autoscroll: bool,
24754    },
24755    TransactionUndone {
24756        transaction_id: clock::Lamport,
24757    },
24758    TransactionBegun {
24759        transaction_id: clock::Lamport,
24760    },
24761    CursorShapeChanged,
24762    BreadcrumbsChanged,
24763    PushedToNavHistory {
24764        anchor: Anchor,
24765        is_deactivate: bool,
24766    },
24767}
24768
24769impl EventEmitter<EditorEvent> for Editor {}
24770
24771impl Focusable for Editor {
24772    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24773        self.focus_handle.clone()
24774    }
24775}
24776
24777impl Render for Editor {
24778    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24779        let settings = ThemeSettings::get_global(cx);
24780
24781        let mut text_style = match self.mode {
24782            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24783                color: cx.theme().colors().editor_foreground,
24784                font_family: settings.ui_font.family.clone(),
24785                font_features: settings.ui_font.features.clone(),
24786                font_fallbacks: settings.ui_font.fallbacks.clone(),
24787                font_size: rems(0.875).into(),
24788                font_weight: settings.ui_font.weight,
24789                line_height: relative(settings.buffer_line_height.value()),
24790                ..Default::default()
24791            },
24792            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24793                color: cx.theme().colors().editor_foreground,
24794                font_family: settings.buffer_font.family.clone(),
24795                font_features: settings.buffer_font.features.clone(),
24796                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24797                font_size: settings.buffer_font_size(cx).into(),
24798                font_weight: settings.buffer_font.weight,
24799                line_height: relative(settings.buffer_line_height.value()),
24800                ..Default::default()
24801            },
24802        };
24803        if let Some(text_style_refinement) = &self.text_style_refinement {
24804            text_style.refine(text_style_refinement)
24805        }
24806
24807        let background = match self.mode {
24808            EditorMode::SingleLine => cx.theme().system().transparent,
24809            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24810            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24811            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24812        };
24813
24814        EditorElement::new(
24815            &cx.entity(),
24816            EditorStyle {
24817                background,
24818                border: cx.theme().colors().border,
24819                local_player: cx.theme().players().local(),
24820                text: text_style,
24821                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24822                syntax: cx.theme().syntax().clone(),
24823                status: cx.theme().status().clone(),
24824                inlay_hints_style: make_inlay_hints_style(cx),
24825                edit_prediction_styles: make_suggestion_styles(cx),
24826                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24827                show_underlines: self.diagnostics_enabled(),
24828            },
24829        )
24830    }
24831}
24832
24833impl EntityInputHandler for Editor {
24834    fn text_for_range(
24835        &mut self,
24836        range_utf16: Range<usize>,
24837        adjusted_range: &mut Option<Range<usize>>,
24838        _: &mut Window,
24839        cx: &mut Context<Self>,
24840    ) -> Option<String> {
24841        let snapshot = self.buffer.read(cx).read(cx);
24842        let start = snapshot.clip_offset_utf16(
24843            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
24844            Bias::Left,
24845        );
24846        let end = snapshot.clip_offset_utf16(
24847            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
24848            Bias::Right,
24849        );
24850        if (start.0.0..end.0.0) != range_utf16 {
24851            adjusted_range.replace(start.0.0..end.0.0);
24852        }
24853        Some(snapshot.text_for_range(start..end).collect())
24854    }
24855
24856    fn selected_text_range(
24857        &mut self,
24858        ignore_disabled_input: bool,
24859        _: &mut Window,
24860        cx: &mut Context<Self>,
24861    ) -> Option<UTF16Selection> {
24862        // Prevent the IME menu from appearing when holding down an alphabetic key
24863        // while input is disabled.
24864        if !ignore_disabled_input && !self.input_enabled {
24865            return None;
24866        }
24867
24868        let selection = self
24869            .selections
24870            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24871        let range = selection.range();
24872
24873        Some(UTF16Selection {
24874            range: range.start.0.0..range.end.0.0,
24875            reversed: selection.reversed,
24876        })
24877    }
24878
24879    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24880        let snapshot = self.buffer.read(cx).read(cx);
24881        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24882        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
24883    }
24884
24885    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24886        self.clear_highlights::<InputComposition>(cx);
24887        self.ime_transaction.take();
24888    }
24889
24890    fn replace_text_in_range(
24891        &mut self,
24892        range_utf16: Option<Range<usize>>,
24893        text: &str,
24894        window: &mut Window,
24895        cx: &mut Context<Self>,
24896    ) {
24897        if !self.input_enabled {
24898            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24899            return;
24900        }
24901
24902        self.transact(window, cx, |this, window, cx| {
24903            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24904                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24905                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24906                Some(this.selection_replacement_ranges(range_utf16, cx))
24907            } else {
24908                this.marked_text_ranges(cx)
24909            };
24910
24911            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24912                let newest_selection_id = this.selections.newest_anchor().id;
24913                this.selections
24914                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24915                    .iter()
24916                    .zip(ranges_to_replace.iter())
24917                    .find_map(|(selection, range)| {
24918                        if selection.id == newest_selection_id {
24919                            Some(
24920                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24921                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24922                            )
24923                        } else {
24924                            None
24925                        }
24926                    })
24927            });
24928
24929            cx.emit(EditorEvent::InputHandled {
24930                utf16_range_to_replace: range_to_replace,
24931                text: text.into(),
24932            });
24933
24934            if let Some(new_selected_ranges) = new_selected_ranges {
24935                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24936                    selections.select_ranges(new_selected_ranges)
24937                });
24938                this.backspace(&Default::default(), window, cx);
24939            }
24940
24941            this.handle_input(text, window, cx);
24942        });
24943
24944        if let Some(transaction) = self.ime_transaction {
24945            self.buffer.update(cx, |buffer, cx| {
24946                buffer.group_until_transaction(transaction, cx);
24947            });
24948        }
24949
24950        self.unmark_text(window, cx);
24951    }
24952
24953    fn replace_and_mark_text_in_range(
24954        &mut self,
24955        range_utf16: Option<Range<usize>>,
24956        text: &str,
24957        new_selected_range_utf16: Option<Range<usize>>,
24958        window: &mut Window,
24959        cx: &mut Context<Self>,
24960    ) {
24961        if !self.input_enabled {
24962            return;
24963        }
24964
24965        let transaction = self.transact(window, cx, |this, window, cx| {
24966            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24967                let snapshot = this.buffer.read(cx).read(cx);
24968                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24969                    for marked_range in &mut marked_ranges {
24970                        marked_range.end = marked_range.start + relative_range_utf16.end;
24971                        marked_range.start += relative_range_utf16.start;
24972                        marked_range.start =
24973                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24974                        marked_range.end =
24975                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24976                    }
24977                }
24978                Some(marked_ranges)
24979            } else if let Some(range_utf16) = range_utf16 {
24980                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24981                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24982                Some(this.selection_replacement_ranges(range_utf16, cx))
24983            } else {
24984                None
24985            };
24986
24987            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24988                let newest_selection_id = this.selections.newest_anchor().id;
24989                this.selections
24990                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24991                    .iter()
24992                    .zip(ranges_to_replace.iter())
24993                    .find_map(|(selection, range)| {
24994                        if selection.id == newest_selection_id {
24995                            Some(
24996                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24997                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24998                            )
24999                        } else {
25000                            None
25001                        }
25002                    })
25003            });
25004
25005            cx.emit(EditorEvent::InputHandled {
25006                utf16_range_to_replace: range_to_replace,
25007                text: text.into(),
25008            });
25009
25010            if let Some(ranges) = ranges_to_replace {
25011                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25012                    s.select_ranges(ranges)
25013                });
25014            }
25015
25016            let marked_ranges = {
25017                let snapshot = this.buffer.read(cx).read(cx);
25018                this.selections
25019                    .disjoint_anchors_arc()
25020                    .iter()
25021                    .map(|selection| {
25022                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25023                    })
25024                    .collect::<Vec<_>>()
25025            };
25026
25027            if text.is_empty() {
25028                this.unmark_text(window, cx);
25029            } else {
25030                this.highlight_text::<InputComposition>(
25031                    marked_ranges.clone(),
25032                    HighlightStyle {
25033                        underline: Some(UnderlineStyle {
25034                            thickness: px(1.),
25035                            color: None,
25036                            wavy: false,
25037                        }),
25038                        ..Default::default()
25039                    },
25040                    cx,
25041                );
25042            }
25043
25044            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25045            let use_autoclose = this.use_autoclose;
25046            let use_auto_surround = this.use_auto_surround;
25047            this.set_use_autoclose(false);
25048            this.set_use_auto_surround(false);
25049            this.handle_input(text, window, cx);
25050            this.set_use_autoclose(use_autoclose);
25051            this.set_use_auto_surround(use_auto_surround);
25052
25053            if let Some(new_selected_range) = new_selected_range_utf16 {
25054                let snapshot = this.buffer.read(cx).read(cx);
25055                let new_selected_ranges = marked_ranges
25056                    .into_iter()
25057                    .map(|marked_range| {
25058                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25059                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25060                            insertion_start.0 + new_selected_range.start,
25061                        ));
25062                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25063                            insertion_start.0 + new_selected_range.end,
25064                        ));
25065                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25066                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25067                    })
25068                    .collect::<Vec<_>>();
25069
25070                drop(snapshot);
25071                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25072                    selections.select_ranges(new_selected_ranges)
25073                });
25074            }
25075        });
25076
25077        self.ime_transaction = self.ime_transaction.or(transaction);
25078        if let Some(transaction) = self.ime_transaction {
25079            self.buffer.update(cx, |buffer, cx| {
25080                buffer.group_until_transaction(transaction, cx);
25081            });
25082        }
25083
25084        if self.text_highlights::<InputComposition>(cx).is_none() {
25085            self.ime_transaction.take();
25086        }
25087    }
25088
25089    fn bounds_for_range(
25090        &mut self,
25091        range_utf16: Range<usize>,
25092        element_bounds: gpui::Bounds<Pixels>,
25093        window: &mut Window,
25094        cx: &mut Context<Self>,
25095    ) -> Option<gpui::Bounds<Pixels>> {
25096        let text_layout_details = self.text_layout_details(window);
25097        let CharacterDimensions {
25098            em_width,
25099            em_advance,
25100            line_height,
25101        } = self.character_dimensions(window);
25102
25103        let snapshot = self.snapshot(window, cx);
25104        let scroll_position = snapshot.scroll_position();
25105        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25106
25107        let start =
25108            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25109        let x = Pixels::from(
25110            ScrollOffset::from(
25111                snapshot.x_for_display_point(start, &text_layout_details)
25112                    + self.gutter_dimensions.full_width(),
25113            ) - scroll_left,
25114        );
25115        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25116
25117        Some(Bounds {
25118            origin: element_bounds.origin + point(x, y),
25119            size: size(em_width, line_height),
25120        })
25121    }
25122
25123    fn character_index_for_point(
25124        &mut self,
25125        point: gpui::Point<Pixels>,
25126        _window: &mut Window,
25127        _cx: &mut Context<Self>,
25128    ) -> Option<usize> {
25129        let position_map = self.last_position_map.as_ref()?;
25130        if !position_map.text_hitbox.contains(&point) {
25131            return None;
25132        }
25133        let display_point = position_map.point_for_position(point).previous_valid;
25134        let anchor = position_map
25135            .snapshot
25136            .display_point_to_anchor(display_point, Bias::Left);
25137        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25138        Some(utf16_offset.0.0)
25139    }
25140
25141    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25142        self.input_enabled
25143    }
25144}
25145
25146trait SelectionExt {
25147    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25148    fn spanned_rows(
25149        &self,
25150        include_end_if_at_line_start: bool,
25151        map: &DisplaySnapshot,
25152    ) -> Range<MultiBufferRow>;
25153}
25154
25155impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25156    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25157        let start = self
25158            .start
25159            .to_point(map.buffer_snapshot())
25160            .to_display_point(map);
25161        let end = self
25162            .end
25163            .to_point(map.buffer_snapshot())
25164            .to_display_point(map);
25165        if self.reversed {
25166            end..start
25167        } else {
25168            start..end
25169        }
25170    }
25171
25172    fn spanned_rows(
25173        &self,
25174        include_end_if_at_line_start: bool,
25175        map: &DisplaySnapshot,
25176    ) -> Range<MultiBufferRow> {
25177        let start = self.start.to_point(map.buffer_snapshot());
25178        let mut end = self.end.to_point(map.buffer_snapshot());
25179        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25180            end.row -= 1;
25181        }
25182
25183        let buffer_start = map.prev_line_boundary(start).0;
25184        let buffer_end = map.next_line_boundary(end).0;
25185        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25186    }
25187}
25188
25189impl<T: InvalidationRegion> InvalidationStack<T> {
25190    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25191    where
25192        S: Clone + ToOffset,
25193    {
25194        while let Some(region) = self.last() {
25195            let all_selections_inside_invalidation_ranges =
25196                if selections.len() == region.ranges().len() {
25197                    selections
25198                        .iter()
25199                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25200                        .all(|(selection, invalidation_range)| {
25201                            let head = selection.head().to_offset(buffer);
25202                            invalidation_range.start <= head && invalidation_range.end >= head
25203                        })
25204                } else {
25205                    false
25206                };
25207
25208            if all_selections_inside_invalidation_ranges {
25209                break;
25210            } else {
25211                self.pop();
25212            }
25213        }
25214    }
25215}
25216
25217impl<T> Default for InvalidationStack<T> {
25218    fn default() -> Self {
25219        Self(Default::default())
25220    }
25221}
25222
25223impl<T> Deref for InvalidationStack<T> {
25224    type Target = Vec<T>;
25225
25226    fn deref(&self) -> &Self::Target {
25227        &self.0
25228    }
25229}
25230
25231impl<T> DerefMut for InvalidationStack<T> {
25232    fn deref_mut(&mut self) -> &mut Self::Target {
25233        &mut self.0
25234    }
25235}
25236
25237impl InvalidationRegion for SnippetState {
25238    fn ranges(&self) -> &[Range<Anchor>] {
25239        &self.ranges[self.active_index]
25240    }
25241}
25242
25243fn edit_prediction_edit_text(
25244    current_snapshot: &BufferSnapshot,
25245    edits: &[(Range<Anchor>, impl AsRef<str>)],
25246    edit_preview: &EditPreview,
25247    include_deletions: bool,
25248    cx: &App,
25249) -> HighlightedText {
25250    let edits = edits
25251        .iter()
25252        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25253        .collect::<Vec<_>>();
25254
25255    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25256}
25257
25258fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25259    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25260    // Just show the raw edit text with basic styling
25261    let mut text = String::new();
25262    let mut highlights = Vec::new();
25263
25264    let insertion_highlight_style = HighlightStyle {
25265        color: Some(cx.theme().colors().text),
25266        ..Default::default()
25267    };
25268
25269    for (_, edit_text) in edits {
25270        let start_offset = text.len();
25271        text.push_str(edit_text);
25272        let end_offset = text.len();
25273
25274        if start_offset < end_offset {
25275            highlights.push((start_offset..end_offset, insertion_highlight_style));
25276        }
25277    }
25278
25279    HighlightedText {
25280        text: text.into(),
25281        highlights,
25282    }
25283}
25284
25285pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25286    match severity {
25287        lsp::DiagnosticSeverity::ERROR => colors.error,
25288        lsp::DiagnosticSeverity::WARNING => colors.warning,
25289        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25290        lsp::DiagnosticSeverity::HINT => colors.info,
25291        _ => colors.ignored,
25292    }
25293}
25294
25295pub fn styled_runs_for_code_label<'a>(
25296    label: &'a CodeLabel,
25297    syntax_theme: &'a theme::SyntaxTheme,
25298    local_player: &'a theme::PlayerColor,
25299) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25300    let fade_out = HighlightStyle {
25301        fade_out: Some(0.35),
25302        ..Default::default()
25303    };
25304
25305    let mut prev_end = label.filter_range.end;
25306    label
25307        .runs
25308        .iter()
25309        .enumerate()
25310        .flat_map(move |(ix, (range, highlight_id))| {
25311            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25312                HighlightStyle {
25313                    color: Some(local_player.cursor),
25314                    ..Default::default()
25315                }
25316            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25317                HighlightStyle {
25318                    background_color: Some(local_player.selection),
25319                    ..Default::default()
25320                }
25321            } else if let Some(style) = highlight_id.style(syntax_theme) {
25322                style
25323            } else {
25324                return Default::default();
25325            };
25326            let muted_style = style.highlight(fade_out);
25327
25328            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25329            if range.start >= label.filter_range.end {
25330                if range.start > prev_end {
25331                    runs.push((prev_end..range.start, fade_out));
25332                }
25333                runs.push((range.clone(), muted_style));
25334            } else if range.end <= label.filter_range.end {
25335                runs.push((range.clone(), style));
25336            } else {
25337                runs.push((range.start..label.filter_range.end, style));
25338                runs.push((label.filter_range.end..range.end, muted_style));
25339            }
25340            prev_end = cmp::max(prev_end, range.end);
25341
25342            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25343                runs.push((prev_end..label.text.len(), fade_out));
25344            }
25345
25346            runs
25347        })
25348}
25349
25350pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25351    let mut prev_index = 0;
25352    let mut prev_codepoint: Option<char> = None;
25353    text.char_indices()
25354        .chain([(text.len(), '\0')])
25355        .filter_map(move |(index, codepoint)| {
25356            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25357            let is_boundary = index == text.len()
25358                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25359                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25360            if is_boundary {
25361                let chunk = &text[prev_index..index];
25362                prev_index = index;
25363                Some(chunk)
25364            } else {
25365                None
25366            }
25367        })
25368}
25369
25370/// Given a string of text immediately before the cursor, iterates over possible
25371/// strings a snippet could match to. More precisely: returns an iterator over
25372/// suffixes of `text` created by splitting at word boundaries (before & after
25373/// every non-word character).
25374///
25375/// Shorter suffixes are returned first.
25376pub(crate) fn snippet_candidate_suffixes(
25377    text: &str,
25378    is_word_char: impl Fn(char) -> bool,
25379) -> impl std::iter::Iterator<Item = &str> {
25380    let mut prev_index = text.len();
25381    let mut prev_codepoint = None;
25382    text.char_indices()
25383        .rev()
25384        .chain([(0, '\0')])
25385        .filter_map(move |(index, codepoint)| {
25386            let prev_index = std::mem::replace(&mut prev_index, index);
25387            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25388            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25389                None
25390            } else {
25391                let chunk = &text[prev_index..]; // go to end of string
25392                Some(chunk)
25393            }
25394        })
25395}
25396
25397pub trait RangeToAnchorExt: Sized {
25398    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25399
25400    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25401        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25402        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25403    }
25404}
25405
25406impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25407    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25408        let start_offset = self.start.to_offset(snapshot);
25409        let end_offset = self.end.to_offset(snapshot);
25410        if start_offset == end_offset {
25411            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25412        } else {
25413            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25414        }
25415    }
25416}
25417
25418pub trait RowExt {
25419    fn as_f64(&self) -> f64;
25420
25421    fn next_row(&self) -> Self;
25422
25423    fn previous_row(&self) -> Self;
25424
25425    fn minus(&self, other: Self) -> u32;
25426}
25427
25428impl RowExt for DisplayRow {
25429    fn as_f64(&self) -> f64 {
25430        self.0 as _
25431    }
25432
25433    fn next_row(&self) -> Self {
25434        Self(self.0 + 1)
25435    }
25436
25437    fn previous_row(&self) -> Self {
25438        Self(self.0.saturating_sub(1))
25439    }
25440
25441    fn minus(&self, other: Self) -> u32 {
25442        self.0 - other.0
25443    }
25444}
25445
25446impl RowExt for MultiBufferRow {
25447    fn as_f64(&self) -> f64 {
25448        self.0 as _
25449    }
25450
25451    fn next_row(&self) -> Self {
25452        Self(self.0 + 1)
25453    }
25454
25455    fn previous_row(&self) -> Self {
25456        Self(self.0.saturating_sub(1))
25457    }
25458
25459    fn minus(&self, other: Self) -> u32 {
25460        self.0 - other.0
25461    }
25462}
25463
25464trait RowRangeExt {
25465    type Row;
25466
25467    fn len(&self) -> usize;
25468
25469    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25470}
25471
25472impl RowRangeExt for Range<MultiBufferRow> {
25473    type Row = MultiBufferRow;
25474
25475    fn len(&self) -> usize {
25476        (self.end.0 - self.start.0) as usize
25477    }
25478
25479    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25480        (self.start.0..self.end.0).map(MultiBufferRow)
25481    }
25482}
25483
25484impl RowRangeExt for Range<DisplayRow> {
25485    type Row = DisplayRow;
25486
25487    fn len(&self) -> usize {
25488        (self.end.0 - self.start.0) as usize
25489    }
25490
25491    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25492        (self.start.0..self.end.0).map(DisplayRow)
25493    }
25494}
25495
25496/// If select range has more than one line, we
25497/// just point the cursor to range.start.
25498fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25499    if range.start.row == range.end.row {
25500        range
25501    } else {
25502        range.start..range.start
25503    }
25504}
25505pub struct KillRing(ClipboardItem);
25506impl Global for KillRing {}
25507
25508const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25509
25510enum BreakpointPromptEditAction {
25511    Log,
25512    Condition,
25513    HitCondition,
25514}
25515
25516struct BreakpointPromptEditor {
25517    pub(crate) prompt: Entity<Editor>,
25518    editor: WeakEntity<Editor>,
25519    breakpoint_anchor: Anchor,
25520    breakpoint: Breakpoint,
25521    edit_action: BreakpointPromptEditAction,
25522    block_ids: HashSet<CustomBlockId>,
25523    editor_margins: Arc<Mutex<EditorMargins>>,
25524    _subscriptions: Vec<Subscription>,
25525}
25526
25527impl BreakpointPromptEditor {
25528    const MAX_LINES: u8 = 4;
25529
25530    fn new(
25531        editor: WeakEntity<Editor>,
25532        breakpoint_anchor: Anchor,
25533        breakpoint: Breakpoint,
25534        edit_action: BreakpointPromptEditAction,
25535        window: &mut Window,
25536        cx: &mut Context<Self>,
25537    ) -> Self {
25538        let base_text = match edit_action {
25539            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25540            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25541            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25542        }
25543        .map(|msg| msg.to_string())
25544        .unwrap_or_default();
25545
25546        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25547        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25548
25549        let prompt = cx.new(|cx| {
25550            let mut prompt = Editor::new(
25551                EditorMode::AutoHeight {
25552                    min_lines: 1,
25553                    max_lines: Some(Self::MAX_LINES as usize),
25554                },
25555                buffer,
25556                None,
25557                window,
25558                cx,
25559            );
25560            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25561            prompt.set_show_cursor_when_unfocused(false, cx);
25562            prompt.set_placeholder_text(
25563                match edit_action {
25564                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25565                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25566                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25567                },
25568                window,
25569                cx,
25570            );
25571
25572            prompt
25573        });
25574
25575        Self {
25576            prompt,
25577            editor,
25578            breakpoint_anchor,
25579            breakpoint,
25580            edit_action,
25581            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25582            block_ids: Default::default(),
25583            _subscriptions: vec![],
25584        }
25585    }
25586
25587    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25588        self.block_ids.extend(block_ids)
25589    }
25590
25591    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25592        if let Some(editor) = self.editor.upgrade() {
25593            let message = self
25594                .prompt
25595                .read(cx)
25596                .buffer
25597                .read(cx)
25598                .as_singleton()
25599                .expect("A multi buffer in breakpoint prompt isn't possible")
25600                .read(cx)
25601                .as_rope()
25602                .to_string();
25603
25604            editor.update(cx, |editor, cx| {
25605                editor.edit_breakpoint_at_anchor(
25606                    self.breakpoint_anchor,
25607                    self.breakpoint.clone(),
25608                    match self.edit_action {
25609                        BreakpointPromptEditAction::Log => {
25610                            BreakpointEditAction::EditLogMessage(message.into())
25611                        }
25612                        BreakpointPromptEditAction::Condition => {
25613                            BreakpointEditAction::EditCondition(message.into())
25614                        }
25615                        BreakpointPromptEditAction::HitCondition => {
25616                            BreakpointEditAction::EditHitCondition(message.into())
25617                        }
25618                    },
25619                    cx,
25620                );
25621
25622                editor.remove_blocks(self.block_ids.clone(), None, cx);
25623                cx.focus_self(window);
25624            });
25625        }
25626    }
25627
25628    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25629        self.editor
25630            .update(cx, |editor, cx| {
25631                editor.remove_blocks(self.block_ids.clone(), None, cx);
25632                window.focus(&editor.focus_handle);
25633            })
25634            .log_err();
25635    }
25636
25637    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25638        let settings = ThemeSettings::get_global(cx);
25639        let text_style = TextStyle {
25640            color: if self.prompt.read(cx).read_only(cx) {
25641                cx.theme().colors().text_disabled
25642            } else {
25643                cx.theme().colors().text
25644            },
25645            font_family: settings.buffer_font.family.clone(),
25646            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25647            font_size: settings.buffer_font_size(cx).into(),
25648            font_weight: settings.buffer_font.weight,
25649            line_height: relative(settings.buffer_line_height.value()),
25650            ..Default::default()
25651        };
25652        EditorElement::new(
25653            &self.prompt,
25654            EditorStyle {
25655                background: cx.theme().colors().editor_background,
25656                local_player: cx.theme().players().local(),
25657                text: text_style,
25658                ..Default::default()
25659            },
25660        )
25661    }
25662}
25663
25664impl Render for BreakpointPromptEditor {
25665    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25666        let editor_margins = *self.editor_margins.lock();
25667        let gutter_dimensions = editor_margins.gutter;
25668        h_flex()
25669            .key_context("Editor")
25670            .bg(cx.theme().colors().editor_background)
25671            .border_y_1()
25672            .border_color(cx.theme().status().info_border)
25673            .size_full()
25674            .py(window.line_height() / 2.5)
25675            .on_action(cx.listener(Self::confirm))
25676            .on_action(cx.listener(Self::cancel))
25677            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25678            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25679    }
25680}
25681
25682impl Focusable for BreakpointPromptEditor {
25683    fn focus_handle(&self, cx: &App) -> FocusHandle {
25684        self.prompt.focus_handle(cx)
25685    }
25686}
25687
25688fn all_edits_insertions_or_deletions(
25689    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25690    snapshot: &MultiBufferSnapshot,
25691) -> bool {
25692    let mut all_insertions = true;
25693    let mut all_deletions = true;
25694
25695    for (range, new_text) in edits.iter() {
25696        let range_is_empty = range.to_offset(snapshot).is_empty();
25697        let text_is_empty = new_text.is_empty();
25698
25699        if range_is_empty != text_is_empty {
25700            if range_is_empty {
25701                all_deletions = false;
25702            } else {
25703                all_insertions = false;
25704            }
25705        } else {
25706            return false;
25707        }
25708
25709        if !all_insertions && !all_deletions {
25710            return false;
25711        }
25712    }
25713    all_insertions || all_deletions
25714}
25715
25716struct MissingEditPredictionKeybindingTooltip;
25717
25718impl Render for MissingEditPredictionKeybindingTooltip {
25719    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25720        ui::tooltip_container(cx, |container, cx| {
25721            container
25722                .flex_shrink_0()
25723                .max_w_80()
25724                .min_h(rems_from_px(124.))
25725                .justify_between()
25726                .child(
25727                    v_flex()
25728                        .flex_1()
25729                        .text_ui_sm(cx)
25730                        .child(Label::new("Conflict with Accept Keybinding"))
25731                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25732                )
25733                .child(
25734                    h_flex()
25735                        .pb_1()
25736                        .gap_1()
25737                        .items_end()
25738                        .w_full()
25739                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25740                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25741                        }))
25742                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25743                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25744                        })),
25745                )
25746        })
25747    }
25748}
25749
25750#[derive(Debug, Clone, Copy, PartialEq)]
25751pub struct LineHighlight {
25752    pub background: Background,
25753    pub border: Option<gpui::Hsla>,
25754    pub include_gutter: bool,
25755    pub type_id: Option<TypeId>,
25756}
25757
25758struct LineManipulationResult {
25759    pub new_text: String,
25760    pub line_count_before: usize,
25761    pub line_count_after: usize,
25762}
25763
25764fn render_diff_hunk_controls(
25765    row: u32,
25766    status: &DiffHunkStatus,
25767    hunk_range: Range<Anchor>,
25768    is_created_file: bool,
25769    line_height: Pixels,
25770    editor: &Entity<Editor>,
25771    _window: &mut Window,
25772    cx: &mut App,
25773) -> AnyElement {
25774    h_flex()
25775        .h(line_height)
25776        .mr_1()
25777        .gap_1()
25778        .px_0p5()
25779        .pb_1()
25780        .border_x_1()
25781        .border_b_1()
25782        .border_color(cx.theme().colors().border_variant)
25783        .rounded_b_lg()
25784        .bg(cx.theme().colors().editor_background)
25785        .gap_1()
25786        .block_mouse_except_scroll()
25787        .shadow_md()
25788        .child(if status.has_secondary_hunk() {
25789            Button::new(("stage", row as u64), "Stage")
25790                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25791                .tooltip({
25792                    let focus_handle = editor.focus_handle(cx);
25793                    move |_window, cx| {
25794                        Tooltip::for_action_in(
25795                            "Stage Hunk",
25796                            &::git::ToggleStaged,
25797                            &focus_handle,
25798                            cx,
25799                        )
25800                    }
25801                })
25802                .on_click({
25803                    let editor = editor.clone();
25804                    move |_event, _window, cx| {
25805                        editor.update(cx, |editor, cx| {
25806                            editor.stage_or_unstage_diff_hunks(
25807                                true,
25808                                vec![hunk_range.start..hunk_range.start],
25809                                cx,
25810                            );
25811                        });
25812                    }
25813                })
25814        } else {
25815            Button::new(("unstage", row as u64), "Unstage")
25816                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25817                .tooltip({
25818                    let focus_handle = editor.focus_handle(cx);
25819                    move |_window, cx| {
25820                        Tooltip::for_action_in(
25821                            "Unstage Hunk",
25822                            &::git::ToggleStaged,
25823                            &focus_handle,
25824                            cx,
25825                        )
25826                    }
25827                })
25828                .on_click({
25829                    let editor = editor.clone();
25830                    move |_event, _window, cx| {
25831                        editor.update(cx, |editor, cx| {
25832                            editor.stage_or_unstage_diff_hunks(
25833                                false,
25834                                vec![hunk_range.start..hunk_range.start],
25835                                cx,
25836                            );
25837                        });
25838                    }
25839                })
25840        })
25841        .child(
25842            Button::new(("restore", row as u64), "Restore")
25843                .tooltip({
25844                    let focus_handle = editor.focus_handle(cx);
25845                    move |_window, cx| {
25846                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25847                    }
25848                })
25849                .on_click({
25850                    let editor = editor.clone();
25851                    move |_event, window, cx| {
25852                        editor.update(cx, |editor, cx| {
25853                            let snapshot = editor.snapshot(window, cx);
25854                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25855                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25856                        });
25857                    }
25858                })
25859                .disabled(is_created_file),
25860        )
25861        .when(
25862            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25863            |el| {
25864                el.child(
25865                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25866                        .shape(IconButtonShape::Square)
25867                        .icon_size(IconSize::Small)
25868                        // .disabled(!has_multiple_hunks)
25869                        .tooltip({
25870                            let focus_handle = editor.focus_handle(cx);
25871                            move |_window, cx| {
25872                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25873                            }
25874                        })
25875                        .on_click({
25876                            let editor = editor.clone();
25877                            move |_event, window, cx| {
25878                                editor.update(cx, |editor, cx| {
25879                                    let snapshot = editor.snapshot(window, cx);
25880                                    let position =
25881                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25882                                    editor.go_to_hunk_before_or_after_position(
25883                                        &snapshot,
25884                                        position,
25885                                        Direction::Next,
25886                                        window,
25887                                        cx,
25888                                    );
25889                                    editor.expand_selected_diff_hunks(cx);
25890                                });
25891                            }
25892                        }),
25893                )
25894                .child(
25895                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25896                        .shape(IconButtonShape::Square)
25897                        .icon_size(IconSize::Small)
25898                        // .disabled(!has_multiple_hunks)
25899                        .tooltip({
25900                            let focus_handle = editor.focus_handle(cx);
25901                            move |_window, cx| {
25902                                Tooltip::for_action_in(
25903                                    "Previous Hunk",
25904                                    &GoToPreviousHunk,
25905                                    &focus_handle,
25906                                    cx,
25907                                )
25908                            }
25909                        })
25910                        .on_click({
25911                            let editor = editor.clone();
25912                            move |_event, window, cx| {
25913                                editor.update(cx, |editor, cx| {
25914                                    let snapshot = editor.snapshot(window, cx);
25915                                    let point =
25916                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25917                                    editor.go_to_hunk_before_or_after_position(
25918                                        &snapshot,
25919                                        point,
25920                                        Direction::Prev,
25921                                        window,
25922                                        cx,
25923                                    );
25924                                    editor.expand_selected_diff_hunks(cx);
25925                                });
25926                            }
25927                        }),
25928                )
25929            },
25930        )
25931        .into_any_element()
25932}
25933
25934pub fn multibuffer_context_lines(cx: &App) -> u32 {
25935    EditorSettings::try_get(cx)
25936        .map(|settings| settings.excerpt_context_lines)
25937        .unwrap_or(2)
25938        .min(32)
25939}