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::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use inlays::Inlay;
   65pub use items::MAX_TAB_TITLE_LEN;
   66pub use lsp::CompletionContext;
   67pub use lsp_ext::lsp_tasks;
   68pub use multi_buffer::{
   69    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   70    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   71    ToPoint,
   72};
   73pub use split::SplittableEditor;
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79    status::FileStatus,
   80};
   81use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   82use anyhow::{Context as _, Result, anyhow};
   83use blink_manager::BlinkManager;
   84use buffer_diff::DiffHunkStatus;
   85use client::{Collaborator, ParticipantIndex, parse_zed_link};
   86use clock::ReplicaId;
   87use code_context_menus::{
   88    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   89    CompletionsMenu, ContextMenuOrigin,
   90};
   91use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   92use convert_case::{Case, Casing};
   93use dap::TelemetrySpawnLocation;
   94use display_map::*;
   95use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   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<RegisteredEditPredictionProvider>,
 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    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1132    edit_prediction_preview: EditPredictionPreview,
 1133    edit_prediction_indent_conflict: bool,
 1134    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1135    next_inlay_id: usize,
 1136    next_color_inlay_id: usize,
 1137    _subscriptions: Vec<Subscription>,
 1138    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1139    gutter_dimensions: GutterDimensions,
 1140    style: Option<EditorStyle>,
 1141    text_style_refinement: Option<TextStyleRefinement>,
 1142    next_editor_action_id: EditorActionId,
 1143    editor_actions: Rc<
 1144        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1145    >,
 1146    use_autoclose: bool,
 1147    use_auto_surround: bool,
 1148    auto_replace_emoji_shortcode: bool,
 1149    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1150    show_git_blame_gutter: bool,
 1151    show_git_blame_inline: bool,
 1152    show_git_blame_inline_delay_task: Option<Task<()>>,
 1153    git_blame_inline_enabled: bool,
 1154    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1155    buffer_serialization: Option<BufferSerialization>,
 1156    show_selection_menu: Option<bool>,
 1157    blame: Option<Entity<GitBlame>>,
 1158    blame_subscription: Option<Subscription>,
 1159    custom_context_menu: Option<
 1160        Box<
 1161            dyn 'static
 1162                + Fn(
 1163                    &mut Self,
 1164                    DisplayPoint,
 1165                    &mut Window,
 1166                    &mut Context<Self>,
 1167                ) -> Option<Entity<ui::ContextMenu>>,
 1168        >,
 1169    >,
 1170    last_bounds: Option<Bounds<Pixels>>,
 1171    last_position_map: Option<Rc<PositionMap>>,
 1172    expect_bounds_change: Option<Bounds<Pixels>>,
 1173    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1174    tasks_update_task: Option<Task<()>>,
 1175    breakpoint_store: Option<Entity<BreakpointStore>>,
 1176    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1177    hovered_diff_hunk_row: Option<DisplayRow>,
 1178    pull_diagnostics_task: Task<()>,
 1179    pull_diagnostics_background_task: Task<()>,
 1180    in_project_search: bool,
 1181    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1182    breadcrumb_header: Option<String>,
 1183    focused_block: Option<FocusedBlock>,
 1184    next_scroll_position: NextScrollCursorCenterTopBottom,
 1185    addons: HashMap<TypeId, Box<dyn Addon>>,
 1186    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1187    load_diff_task: Option<Shared<Task<()>>>,
 1188    /// Whether we are temporarily displaying a diff other than git's
 1189    temporary_diff_override: bool,
 1190    selection_mark_mode: bool,
 1191    toggle_fold_multiple_buffers: Task<()>,
 1192    _scroll_cursor_center_top_bottom_task: Task<()>,
 1193    serialize_selections: Task<()>,
 1194    serialize_folds: Task<()>,
 1195    mouse_cursor_hidden: bool,
 1196    minimap: Option<Entity<Self>>,
 1197    hide_mouse_mode: HideMouseMode,
 1198    pub change_list: ChangeList,
 1199    inline_value_cache: InlineValueCache,
 1200
 1201    selection_drag_state: SelectionDragState,
 1202    colors: Option<LspColorData>,
 1203    post_scroll_update: Task<()>,
 1204    refresh_colors_task: Task<()>,
 1205    inlay_hints: Option<LspInlayHintData>,
 1206    folding_newlines: Task<()>,
 1207    select_next_is_case_sensitive: Option<bool>,
 1208    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1209    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1210    accent_data: Option<AccentData>,
 1211    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1212    use_base_text_line_numbers: bool,
 1213}
 1214
 1215#[derive(Debug, PartialEq)]
 1216struct AccentData {
 1217    colors: AccentColors,
 1218    overrides: Vec<SharedString>,
 1219}
 1220
 1221fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1222    if debounce_ms > 0 {
 1223        Some(Duration::from_millis(debounce_ms))
 1224    } else {
 1225        None
 1226    }
 1227}
 1228
 1229#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1230enum NextScrollCursorCenterTopBottom {
 1231    #[default]
 1232    Center,
 1233    Top,
 1234    Bottom,
 1235}
 1236
 1237impl NextScrollCursorCenterTopBottom {
 1238    fn next(&self) -> Self {
 1239        match self {
 1240            Self::Center => Self::Top,
 1241            Self::Top => Self::Bottom,
 1242            Self::Bottom => Self::Center,
 1243        }
 1244    }
 1245}
 1246
 1247#[derive(Clone)]
 1248pub struct EditorSnapshot {
 1249    pub mode: EditorMode,
 1250    show_gutter: bool,
 1251    show_line_numbers: Option<bool>,
 1252    show_git_diff_gutter: Option<bool>,
 1253    show_code_actions: Option<bool>,
 1254    show_runnables: Option<bool>,
 1255    show_breakpoints: Option<bool>,
 1256    git_blame_gutter_max_author_length: Option<usize>,
 1257    pub display_snapshot: DisplaySnapshot,
 1258    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1259    is_focused: bool,
 1260    scroll_anchor: ScrollAnchor,
 1261    ongoing_scroll: OngoingScroll,
 1262    current_line_highlight: CurrentLineHighlight,
 1263    gutter_hovered: bool,
 1264}
 1265
 1266#[derive(Default, Debug, Clone, Copy)]
 1267pub struct GutterDimensions {
 1268    pub left_padding: Pixels,
 1269    pub right_padding: Pixels,
 1270    pub width: Pixels,
 1271    pub margin: Pixels,
 1272    pub git_blame_entries_width: Option<Pixels>,
 1273}
 1274
 1275impl GutterDimensions {
 1276    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1277        Self {
 1278            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1279            ..Default::default()
 1280        }
 1281    }
 1282
 1283    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1284        -cx.text_system().descent(font_id, font_size)
 1285    }
 1286    /// The full width of the space taken up by the gutter.
 1287    pub fn full_width(&self) -> Pixels {
 1288        self.margin + self.width
 1289    }
 1290
 1291    /// The width of the space reserved for the fold indicators,
 1292    /// use alongside 'justify_end' and `gutter_width` to
 1293    /// right align content with the line numbers
 1294    pub fn fold_area_width(&self) -> Pixels {
 1295        self.margin + self.right_padding
 1296    }
 1297}
 1298
 1299struct CharacterDimensions {
 1300    em_width: Pixels,
 1301    em_advance: Pixels,
 1302    line_height: Pixels,
 1303}
 1304
 1305#[derive(Debug)]
 1306pub struct RemoteSelection {
 1307    pub replica_id: ReplicaId,
 1308    pub selection: Selection<Anchor>,
 1309    pub cursor_shape: CursorShape,
 1310    pub collaborator_id: CollaboratorId,
 1311    pub line_mode: bool,
 1312    pub user_name: Option<SharedString>,
 1313    pub color: PlayerColor,
 1314}
 1315
 1316#[derive(Clone, Debug)]
 1317struct SelectionHistoryEntry {
 1318    selections: Arc<[Selection<Anchor>]>,
 1319    select_next_state: Option<SelectNextState>,
 1320    select_prev_state: Option<SelectNextState>,
 1321    add_selections_state: Option<AddSelectionsState>,
 1322}
 1323
 1324#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1325enum SelectionHistoryMode {
 1326    #[default]
 1327    Normal,
 1328    Undoing,
 1329    Redoing,
 1330    Skipping,
 1331}
 1332
 1333#[derive(Clone, PartialEq, Eq, Hash)]
 1334struct HoveredCursor {
 1335    replica_id: ReplicaId,
 1336    selection_id: usize,
 1337}
 1338
 1339#[derive(Debug)]
 1340/// SelectionEffects controls the side-effects of updating the selection.
 1341///
 1342/// The default behaviour does "what you mostly want":
 1343/// - it pushes to the nav history if the cursor moved by >10 lines
 1344/// - it re-triggers completion requests
 1345/// - it scrolls to fit
 1346///
 1347/// You might want to modify these behaviours. For example when doing a "jump"
 1348/// like go to definition, we always want to add to nav history; but when scrolling
 1349/// in vim mode we never do.
 1350///
 1351/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1352/// move.
 1353#[derive(Clone)]
 1354pub struct SelectionEffects {
 1355    nav_history: Option<bool>,
 1356    completions: bool,
 1357    scroll: Option<Autoscroll>,
 1358}
 1359
 1360impl Default for SelectionEffects {
 1361    fn default() -> Self {
 1362        Self {
 1363            nav_history: None,
 1364            completions: true,
 1365            scroll: Some(Autoscroll::fit()),
 1366        }
 1367    }
 1368}
 1369impl SelectionEffects {
 1370    pub fn scroll(scroll: Autoscroll) -> Self {
 1371        Self {
 1372            scroll: Some(scroll),
 1373            ..Default::default()
 1374        }
 1375    }
 1376
 1377    pub fn no_scroll() -> Self {
 1378        Self {
 1379            scroll: None,
 1380            ..Default::default()
 1381        }
 1382    }
 1383
 1384    pub fn completions(self, completions: bool) -> Self {
 1385        Self {
 1386            completions,
 1387            ..self
 1388        }
 1389    }
 1390
 1391    pub fn nav_history(self, nav_history: bool) -> Self {
 1392        Self {
 1393            nav_history: Some(nav_history),
 1394            ..self
 1395        }
 1396    }
 1397}
 1398
 1399struct DeferredSelectionEffectsState {
 1400    changed: bool,
 1401    effects: SelectionEffects,
 1402    old_cursor_position: Anchor,
 1403    history_entry: SelectionHistoryEntry,
 1404}
 1405
 1406#[derive(Default)]
 1407struct SelectionHistory {
 1408    #[allow(clippy::type_complexity)]
 1409    selections_by_transaction:
 1410        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1411    mode: SelectionHistoryMode,
 1412    undo_stack: VecDeque<SelectionHistoryEntry>,
 1413    redo_stack: VecDeque<SelectionHistoryEntry>,
 1414}
 1415
 1416impl SelectionHistory {
 1417    #[track_caller]
 1418    fn insert_transaction(
 1419        &mut self,
 1420        transaction_id: TransactionId,
 1421        selections: Arc<[Selection<Anchor>]>,
 1422    ) {
 1423        if selections.is_empty() {
 1424            log::error!(
 1425                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1426                std::panic::Location::caller()
 1427            );
 1428            return;
 1429        }
 1430        self.selections_by_transaction
 1431            .insert(transaction_id, (selections, None));
 1432    }
 1433
 1434    #[allow(clippy::type_complexity)]
 1435    fn transaction(
 1436        &self,
 1437        transaction_id: TransactionId,
 1438    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1439        self.selections_by_transaction.get(&transaction_id)
 1440    }
 1441
 1442    #[allow(clippy::type_complexity)]
 1443    fn transaction_mut(
 1444        &mut self,
 1445        transaction_id: TransactionId,
 1446    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1447        self.selections_by_transaction.get_mut(&transaction_id)
 1448    }
 1449
 1450    fn push(&mut self, entry: SelectionHistoryEntry) {
 1451        if !entry.selections.is_empty() {
 1452            match self.mode {
 1453                SelectionHistoryMode::Normal => {
 1454                    self.push_undo(entry);
 1455                    self.redo_stack.clear();
 1456                }
 1457                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1458                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1459                SelectionHistoryMode::Skipping => {}
 1460            }
 1461        }
 1462    }
 1463
 1464    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1465        if self
 1466            .undo_stack
 1467            .back()
 1468            .is_none_or(|e| e.selections != entry.selections)
 1469        {
 1470            self.undo_stack.push_back(entry);
 1471            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1472                self.undo_stack.pop_front();
 1473            }
 1474        }
 1475    }
 1476
 1477    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1478        if self
 1479            .redo_stack
 1480            .back()
 1481            .is_none_or(|e| e.selections != entry.selections)
 1482        {
 1483            self.redo_stack.push_back(entry);
 1484            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1485                self.redo_stack.pop_front();
 1486            }
 1487        }
 1488    }
 1489}
 1490
 1491#[derive(Clone, Copy)]
 1492pub struct RowHighlightOptions {
 1493    pub autoscroll: bool,
 1494    pub include_gutter: bool,
 1495}
 1496
 1497impl Default for RowHighlightOptions {
 1498    fn default() -> Self {
 1499        Self {
 1500            autoscroll: Default::default(),
 1501            include_gutter: true,
 1502        }
 1503    }
 1504}
 1505
 1506struct RowHighlight {
 1507    index: usize,
 1508    range: Range<Anchor>,
 1509    color: Hsla,
 1510    options: RowHighlightOptions,
 1511    type_id: TypeId,
 1512}
 1513
 1514#[derive(Clone, Debug)]
 1515struct AddSelectionsState {
 1516    groups: Vec<AddSelectionsGroup>,
 1517}
 1518
 1519#[derive(Clone, Debug)]
 1520struct AddSelectionsGroup {
 1521    above: bool,
 1522    stack: Vec<usize>,
 1523}
 1524
 1525#[derive(Clone)]
 1526struct SelectNextState {
 1527    query: AhoCorasick,
 1528    wordwise: bool,
 1529    done: bool,
 1530}
 1531
 1532impl std::fmt::Debug for SelectNextState {
 1533    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1534        f.debug_struct(std::any::type_name::<Self>())
 1535            .field("wordwise", &self.wordwise)
 1536            .field("done", &self.done)
 1537            .finish()
 1538    }
 1539}
 1540
 1541#[derive(Debug)]
 1542struct AutocloseRegion {
 1543    selection_id: usize,
 1544    range: Range<Anchor>,
 1545    pair: BracketPair,
 1546}
 1547
 1548#[derive(Debug)]
 1549struct SnippetState {
 1550    ranges: Vec<Vec<Range<Anchor>>>,
 1551    active_index: usize,
 1552    choices: Vec<Option<Vec<String>>>,
 1553}
 1554
 1555#[doc(hidden)]
 1556pub struct RenameState {
 1557    pub range: Range<Anchor>,
 1558    pub old_name: Arc<str>,
 1559    pub editor: Entity<Editor>,
 1560    block_id: CustomBlockId,
 1561}
 1562
 1563struct InvalidationStack<T>(Vec<T>);
 1564
 1565struct RegisteredEditPredictionProvider {
 1566    provider: Arc<dyn EditPredictionProviderHandle>,
 1567    _subscription: Subscription,
 1568}
 1569
 1570#[derive(Debug, PartialEq, Eq)]
 1571pub struct ActiveDiagnosticGroup {
 1572    pub active_range: Range<Anchor>,
 1573    pub active_message: String,
 1574    pub group_id: usize,
 1575    pub blocks: HashSet<CustomBlockId>,
 1576}
 1577
 1578#[derive(Debug, PartialEq, Eq)]
 1579
 1580pub(crate) enum ActiveDiagnostic {
 1581    None,
 1582    All,
 1583    Group(ActiveDiagnosticGroup),
 1584}
 1585
 1586#[derive(Serialize, Deserialize, Clone, Debug)]
 1587pub struct ClipboardSelection {
 1588    /// The number of bytes in this selection.
 1589    pub len: usize,
 1590    /// Whether this was a full-line selection.
 1591    pub is_entire_line: bool,
 1592    /// The indentation of the first line when this content was originally copied.
 1593    pub first_line_indent: u32,
 1594}
 1595
 1596// selections, scroll behavior, was newest selection reversed
 1597type SelectSyntaxNodeHistoryState = (
 1598    Box<[Selection<MultiBufferOffset>]>,
 1599    SelectSyntaxNodeScrollBehavior,
 1600    bool,
 1601);
 1602
 1603#[derive(Default)]
 1604struct SelectSyntaxNodeHistory {
 1605    stack: Vec<SelectSyntaxNodeHistoryState>,
 1606    // disable temporarily to allow changing selections without losing the stack
 1607    pub disable_clearing: bool,
 1608}
 1609
 1610impl SelectSyntaxNodeHistory {
 1611    pub fn try_clear(&mut self) {
 1612        if !self.disable_clearing {
 1613            self.stack.clear();
 1614        }
 1615    }
 1616
 1617    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1618        self.stack.push(selection);
 1619    }
 1620
 1621    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1622        self.stack.pop()
 1623    }
 1624}
 1625
 1626enum SelectSyntaxNodeScrollBehavior {
 1627    CursorTop,
 1628    FitSelection,
 1629    CursorBottom,
 1630}
 1631
 1632#[derive(Debug)]
 1633pub(crate) struct NavigationData {
 1634    cursor_anchor: Anchor,
 1635    cursor_position: Point,
 1636    scroll_anchor: ScrollAnchor,
 1637    scroll_top_row: u32,
 1638}
 1639
 1640#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1641pub enum GotoDefinitionKind {
 1642    Symbol,
 1643    Declaration,
 1644    Type,
 1645    Implementation,
 1646}
 1647
 1648pub enum FormatTarget {
 1649    Buffers(HashSet<Entity<Buffer>>),
 1650    Ranges(Vec<Range<MultiBufferPoint>>),
 1651}
 1652
 1653pub(crate) struct FocusedBlock {
 1654    id: BlockId,
 1655    focus_handle: WeakFocusHandle,
 1656}
 1657
 1658#[derive(Clone, Debug)]
 1659enum JumpData {
 1660    MultiBufferRow {
 1661        row: MultiBufferRow,
 1662        line_offset_from_top: u32,
 1663    },
 1664    MultiBufferPoint {
 1665        excerpt_id: ExcerptId,
 1666        position: Point,
 1667        anchor: text::Anchor,
 1668        line_offset_from_top: u32,
 1669    },
 1670}
 1671
 1672pub enum MultibufferSelectionMode {
 1673    First,
 1674    All,
 1675}
 1676
 1677#[derive(Clone, Copy, Debug, Default)]
 1678pub struct RewrapOptions {
 1679    pub override_language_settings: bool,
 1680    pub preserve_existing_whitespace: bool,
 1681}
 1682
 1683impl Editor {
 1684    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1685        let buffer = cx.new(|cx| Buffer::local("", cx));
 1686        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1687        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1688    }
 1689
 1690    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1691        let buffer = cx.new(|cx| Buffer::local("", cx));
 1692        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1693        Self::new(EditorMode::full(), buffer, None, window, cx)
 1694    }
 1695
 1696    pub fn auto_height(
 1697        min_lines: usize,
 1698        max_lines: usize,
 1699        window: &mut Window,
 1700        cx: &mut Context<Self>,
 1701    ) -> Self {
 1702        let buffer = cx.new(|cx| Buffer::local("", cx));
 1703        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1704        Self::new(
 1705            EditorMode::AutoHeight {
 1706                min_lines,
 1707                max_lines: Some(max_lines),
 1708            },
 1709            buffer,
 1710            None,
 1711            window,
 1712            cx,
 1713        )
 1714    }
 1715
 1716    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1717    /// The editor grows as tall as needed to fit its content.
 1718    pub fn auto_height_unbounded(
 1719        min_lines: usize,
 1720        window: &mut Window,
 1721        cx: &mut Context<Self>,
 1722    ) -> Self {
 1723        let buffer = cx.new(|cx| Buffer::local("", cx));
 1724        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1725        Self::new(
 1726            EditorMode::AutoHeight {
 1727                min_lines,
 1728                max_lines: None,
 1729            },
 1730            buffer,
 1731            None,
 1732            window,
 1733            cx,
 1734        )
 1735    }
 1736
 1737    pub fn for_buffer(
 1738        buffer: Entity<Buffer>,
 1739        project: Option<Entity<Project>>,
 1740        window: &mut Window,
 1741        cx: &mut Context<Self>,
 1742    ) -> Self {
 1743        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1744        Self::new(EditorMode::full(), buffer, project, window, cx)
 1745    }
 1746
 1747    pub fn for_multibuffer(
 1748        buffer: Entity<MultiBuffer>,
 1749        project: Option<Entity<Project>>,
 1750        window: &mut Window,
 1751        cx: &mut Context<Self>,
 1752    ) -> Self {
 1753        Self::new(EditorMode::full(), buffer, project, window, cx)
 1754    }
 1755
 1756    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1757        let mut clone = Self::new(
 1758            self.mode.clone(),
 1759            self.buffer.clone(),
 1760            self.project.clone(),
 1761            window,
 1762            cx,
 1763        );
 1764        self.display_map.update(cx, |display_map, cx| {
 1765            let snapshot = display_map.snapshot(cx);
 1766            clone.display_map.update(cx, |display_map, cx| {
 1767                display_map.set_state(&snapshot, cx);
 1768            });
 1769        });
 1770        clone.folds_did_change(cx);
 1771        clone.selections.clone_state(&self.selections);
 1772        clone.scroll_manager.clone_state(&self.scroll_manager);
 1773        clone.searchable = self.searchable;
 1774        clone.read_only = self.read_only;
 1775        clone
 1776    }
 1777
 1778    pub fn new(
 1779        mode: EditorMode,
 1780        buffer: Entity<MultiBuffer>,
 1781        project: Option<Entity<Project>>,
 1782        window: &mut Window,
 1783        cx: &mut Context<Self>,
 1784    ) -> Self {
 1785        Editor::new_internal(mode, buffer, project, None, window, cx)
 1786    }
 1787
 1788    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1789        let multi_buffer = self.buffer().read(cx);
 1790        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1791        let multi_buffer_visible_start = self
 1792            .scroll_manager
 1793            .anchor()
 1794            .anchor
 1795            .to_point(&multi_buffer_snapshot);
 1796        let max_row = multi_buffer_snapshot.max_point().row;
 1797
 1798        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1799        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1800
 1801        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1802            let outline_items = buffer
 1803                .outline_items_containing(
 1804                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1805                    true,
 1806                    self.style().map(|style| style.syntax.as_ref()),
 1807                )
 1808                .into_iter()
 1809                .map(|outline_item| OutlineItem {
 1810                    depth: outline_item.depth,
 1811                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1812                    source_range_for_text: Anchor::range_in_buffer(
 1813                        *excerpt_id,
 1814                        outline_item.source_range_for_text,
 1815                    ),
 1816                    text: outline_item.text,
 1817                    highlight_ranges: outline_item.highlight_ranges,
 1818                    name_ranges: outline_item.name_ranges,
 1819                    body_range: outline_item
 1820                        .body_range
 1821                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1822                    annotation_range: outline_item
 1823                        .annotation_range
 1824                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1825                });
 1826            return Some(outline_items.collect());
 1827        }
 1828
 1829        None
 1830    }
 1831
 1832    fn new_internal(
 1833        mode: EditorMode,
 1834        multi_buffer: Entity<MultiBuffer>,
 1835        project: Option<Entity<Project>>,
 1836        display_map: Option<Entity<DisplayMap>>,
 1837        window: &mut Window,
 1838        cx: &mut Context<Self>,
 1839    ) -> Self {
 1840        debug_assert!(
 1841            display_map.is_none() || mode.is_minimap(),
 1842            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1843        );
 1844
 1845        let full_mode = mode.is_full();
 1846        let is_minimap = mode.is_minimap();
 1847        let diagnostics_max_severity = if full_mode {
 1848            EditorSettings::get_global(cx)
 1849                .diagnostics_max_severity
 1850                .unwrap_or(DiagnosticSeverity::Hint)
 1851        } else {
 1852            DiagnosticSeverity::Off
 1853        };
 1854        let style = window.text_style();
 1855        let font_size = style.font_size.to_pixels(window.rem_size());
 1856        let editor = cx.entity().downgrade();
 1857        let fold_placeholder = FoldPlaceholder {
 1858            constrain_width: false,
 1859            render: Arc::new(move |fold_id, fold_range, cx| {
 1860                let editor = editor.clone();
 1861                div()
 1862                    .id(fold_id)
 1863                    .bg(cx.theme().colors().ghost_element_background)
 1864                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1865                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1866                    .rounded_xs()
 1867                    .size_full()
 1868                    .cursor_pointer()
 1869                    .child("")
 1870                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1871                    .on_click(move |_, _window, cx| {
 1872                        editor
 1873                            .update(cx, |editor, cx| {
 1874                                editor.unfold_ranges(
 1875                                    &[fold_range.start..fold_range.end],
 1876                                    true,
 1877                                    false,
 1878                                    cx,
 1879                                );
 1880                                cx.stop_propagation();
 1881                            })
 1882                            .ok();
 1883                    })
 1884                    .into_any()
 1885            }),
 1886            merge_adjacent: true,
 1887            ..FoldPlaceholder::default()
 1888        };
 1889        let display_map = display_map.unwrap_or_else(|| {
 1890            cx.new(|cx| {
 1891                DisplayMap::new(
 1892                    multi_buffer.clone(),
 1893                    style.font(),
 1894                    font_size,
 1895                    None,
 1896                    FILE_HEADER_HEIGHT,
 1897                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1898                    fold_placeholder,
 1899                    diagnostics_max_severity,
 1900                    cx,
 1901                )
 1902            })
 1903        });
 1904
 1905        let selections = SelectionsCollection::new();
 1906
 1907        let blink_manager = cx.new(|cx| {
 1908            let mut blink_manager = BlinkManager::new(
 1909                CURSOR_BLINK_INTERVAL,
 1910                |cx| EditorSettings::get_global(cx).cursor_blink,
 1911                cx,
 1912            );
 1913            if is_minimap {
 1914                blink_manager.disable(cx);
 1915            }
 1916            blink_manager
 1917        });
 1918
 1919        let soft_wrap_mode_override =
 1920            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1921
 1922        let mut project_subscriptions = Vec::new();
 1923        if full_mode && let Some(project) = project.as_ref() {
 1924            project_subscriptions.push(cx.subscribe_in(
 1925                project,
 1926                window,
 1927                |editor, _, event, window, cx| match event {
 1928                    project::Event::RefreshCodeLens => {
 1929                        // we always query lens with actions, without storing them, always refreshing them
 1930                    }
 1931                    project::Event::RefreshInlayHints {
 1932                        server_id,
 1933                        request_id,
 1934                    } => {
 1935                        editor.refresh_inlay_hints(
 1936                            InlayHintRefreshReason::RefreshRequested {
 1937                                server_id: *server_id,
 1938                                request_id: *request_id,
 1939                            },
 1940                            cx,
 1941                        );
 1942                    }
 1943                    project::Event::LanguageServerRemoved(..) => {
 1944                        if editor.tasks_update_task.is_none() {
 1945                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1946                        }
 1947                        editor.registered_buffers.clear();
 1948                        editor.register_visible_buffers(cx);
 1949                    }
 1950                    project::Event::LanguageServerAdded(..) => {
 1951                        if editor.tasks_update_task.is_none() {
 1952                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1953                        }
 1954                    }
 1955                    project::Event::SnippetEdit(id, snippet_edits) => {
 1956                        // todo(lw): Non singletons
 1957                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 1958                            let snapshot = buffer.read(cx).snapshot();
 1959                            let focus_handle = editor.focus_handle(cx);
 1960                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 1961                                for (range, snippet) in snippet_edits {
 1962                                    let buffer_range =
 1963                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1964                                    editor
 1965                                        .insert_snippet(
 1966                                            &[MultiBufferOffset(buffer_range.start)
 1967                                                ..MultiBufferOffset(buffer_range.end)],
 1968                                            snippet.clone(),
 1969                                            window,
 1970                                            cx,
 1971                                        )
 1972                                        .ok();
 1973                                }
 1974                            }
 1975                        }
 1976                    }
 1977                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1978                        let buffer_id = *buffer_id;
 1979                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1980                            editor.register_buffer(buffer_id, cx);
 1981                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1982                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1983                            refresh_linked_ranges(editor, window, cx);
 1984                            editor.refresh_code_actions(window, cx);
 1985                            editor.refresh_document_highlights(cx);
 1986                        }
 1987                    }
 1988
 1989                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1990                        let Some(workspace) = editor.workspace() else {
 1991                            return;
 1992                        };
 1993                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1994                        else {
 1995                            return;
 1996                        };
 1997
 1998                        if active_editor.entity_id() == cx.entity_id() {
 1999                            let entity_id = cx.entity_id();
 2000                            workspace.update(cx, |this, cx| {
 2001                                this.panes_mut()
 2002                                    .iter_mut()
 2003                                    .filter(|pane| pane.entity_id() != entity_id)
 2004                                    .for_each(|p| {
 2005                                        p.update(cx, |pane, _| {
 2006                                            pane.nav_history_mut().rename_item(
 2007                                                entity_id,
 2008                                                project_path.clone(),
 2009                                                abs_path.clone().into(),
 2010                                            );
 2011                                        })
 2012                                    });
 2013                            });
 2014                            let edited_buffers_already_open = {
 2015                                let other_editors: Vec<Entity<Editor>> = workspace
 2016                                    .read(cx)
 2017                                    .panes()
 2018                                    .iter()
 2019                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 2020                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2021                                    .collect();
 2022
 2023                                transaction.0.keys().all(|buffer| {
 2024                                    other_editors.iter().any(|editor| {
 2025                                        let multi_buffer = editor.read(cx).buffer();
 2026                                        multi_buffer.read(cx).is_singleton()
 2027                                            && multi_buffer.read(cx).as_singleton().map_or(
 2028                                                false,
 2029                                                |singleton| {
 2030                                                    singleton.entity_id() == buffer.entity_id()
 2031                                                },
 2032                                            )
 2033                                    })
 2034                                })
 2035                            };
 2036                            if !edited_buffers_already_open {
 2037                                let workspace = workspace.downgrade();
 2038                                let transaction = transaction.clone();
 2039                                cx.defer_in(window, move |_, window, cx| {
 2040                                    cx.spawn_in(window, async move |editor, cx| {
 2041                                        Self::open_project_transaction(
 2042                                            &editor,
 2043                                            workspace,
 2044                                            transaction,
 2045                                            "Rename".to_string(),
 2046                                            cx,
 2047                                        )
 2048                                        .await
 2049                                        .ok()
 2050                                    })
 2051                                    .detach();
 2052                                });
 2053                            }
 2054                        }
 2055                    }
 2056
 2057                    _ => {}
 2058                },
 2059            ));
 2060            if let Some(task_inventory) = project
 2061                .read(cx)
 2062                .task_store()
 2063                .read(cx)
 2064                .task_inventory()
 2065                .cloned()
 2066            {
 2067                project_subscriptions.push(cx.observe_in(
 2068                    &task_inventory,
 2069                    window,
 2070                    |editor, _, window, cx| {
 2071                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2072                    },
 2073                ));
 2074            };
 2075
 2076            project_subscriptions.push(cx.subscribe_in(
 2077                &project.read(cx).breakpoint_store(),
 2078                window,
 2079                |editor, _, event, window, cx| match event {
 2080                    BreakpointStoreEvent::ClearDebugLines => {
 2081                        editor.clear_row_highlights::<ActiveDebugLine>();
 2082                        editor.refresh_inline_values(cx);
 2083                    }
 2084                    BreakpointStoreEvent::SetDebugLine => {
 2085                        if editor.go_to_active_debug_line(window, cx) {
 2086                            cx.stop_propagation();
 2087                        }
 2088
 2089                        editor.refresh_inline_values(cx);
 2090                    }
 2091                    _ => {}
 2092                },
 2093            ));
 2094            let git_store = project.read(cx).git_store().clone();
 2095            let project = project.clone();
 2096            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2097                if let GitStoreEvent::RepositoryAdded = event {
 2098                    this.load_diff_task = Some(
 2099                        update_uncommitted_diff_for_buffer(
 2100                            cx.entity(),
 2101                            &project,
 2102                            this.buffer.read(cx).all_buffers(),
 2103                            this.buffer.clone(),
 2104                            cx,
 2105                        )
 2106                        .shared(),
 2107                    );
 2108                }
 2109            }));
 2110        }
 2111
 2112        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2113
 2114        let inlay_hint_settings =
 2115            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2116        let focus_handle = cx.focus_handle();
 2117        if !is_minimap {
 2118            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2119                .detach();
 2120            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2121                .detach();
 2122            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2123                .detach();
 2124            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2125                .detach();
 2126            cx.observe_pending_input(window, Self::observe_pending_input)
 2127                .detach();
 2128        }
 2129
 2130        let show_indent_guides =
 2131            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2132                Some(false)
 2133            } else {
 2134                None
 2135            };
 2136
 2137        let breakpoint_store = match (&mode, project.as_ref()) {
 2138            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2139            _ => None,
 2140        };
 2141
 2142        let mut code_action_providers = Vec::new();
 2143        let mut load_uncommitted_diff = None;
 2144        if let Some(project) = project.clone() {
 2145            load_uncommitted_diff = Some(
 2146                update_uncommitted_diff_for_buffer(
 2147                    cx.entity(),
 2148                    &project,
 2149                    multi_buffer.read(cx).all_buffers(),
 2150                    multi_buffer.clone(),
 2151                    cx,
 2152                )
 2153                .shared(),
 2154            );
 2155            code_action_providers.push(Rc::new(project) as Rc<_>);
 2156        }
 2157
 2158        let mut editor = Self {
 2159            focus_handle,
 2160            show_cursor_when_unfocused: false,
 2161            last_focused_descendant: None,
 2162            buffer: multi_buffer.clone(),
 2163            display_map: display_map.clone(),
 2164            placeholder_display_map: None,
 2165            selections,
 2166            scroll_manager: ScrollManager::new(cx),
 2167            columnar_selection_state: None,
 2168            add_selections_state: None,
 2169            select_next_state: None,
 2170            select_prev_state: None,
 2171            selection_history: SelectionHistory::default(),
 2172            defer_selection_effects: false,
 2173            deferred_selection_effects_state: None,
 2174            autoclose_regions: Vec::new(),
 2175            snippet_stack: InvalidationStack::default(),
 2176            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2177            ime_transaction: None,
 2178            active_diagnostics: ActiveDiagnostic::None,
 2179            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2180            inline_diagnostics_update: Task::ready(()),
 2181            inline_diagnostics: Vec::new(),
 2182            soft_wrap_mode_override,
 2183            diagnostics_max_severity,
 2184            hard_wrap: None,
 2185            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2186            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2187            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2188            project,
 2189            blink_manager: blink_manager.clone(),
 2190            show_local_selections: true,
 2191            show_scrollbars: ScrollbarAxes {
 2192                horizontal: full_mode,
 2193                vertical: full_mode,
 2194            },
 2195            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2196            offset_content: !matches!(mode, EditorMode::SingleLine),
 2197            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2198            show_gutter: full_mode,
 2199            show_line_numbers: (!full_mode).then_some(false),
 2200            use_relative_line_numbers: None,
 2201            disable_expand_excerpt_buttons: !full_mode,
 2202            show_git_diff_gutter: None,
 2203            show_code_actions: None,
 2204            show_runnables: None,
 2205            show_breakpoints: None,
 2206            show_wrap_guides: None,
 2207            show_indent_guides,
 2208            buffers_with_disabled_indent_guides: HashSet::default(),
 2209            highlight_order: 0,
 2210            highlighted_rows: HashMap::default(),
 2211            background_highlights: HashMap::default(),
 2212            gutter_highlights: HashMap::default(),
 2213            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2214            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2215            nav_history: None,
 2216            context_menu: RefCell::new(None),
 2217            context_menu_options: None,
 2218            mouse_context_menu: None,
 2219            completion_tasks: Vec::new(),
 2220            inline_blame_popover: None,
 2221            inline_blame_popover_show_task: None,
 2222            signature_help_state: SignatureHelpState::default(),
 2223            auto_signature_help: None,
 2224            find_all_references_task_sources: Vec::new(),
 2225            next_completion_id: 0,
 2226            next_inlay_id: 0,
 2227            code_action_providers,
 2228            available_code_actions: None,
 2229            code_actions_task: None,
 2230            quick_selection_highlight_task: None,
 2231            debounced_selection_highlight_task: None,
 2232            document_highlights_task: None,
 2233            linked_editing_range_task: None,
 2234            pending_rename: None,
 2235            searchable: !is_minimap,
 2236            cursor_shape: EditorSettings::get_global(cx)
 2237                .cursor_shape
 2238                .unwrap_or_default(),
 2239            current_line_highlight: None,
 2240            autoindent_mode: Some(AutoindentMode::EachLine),
 2241            collapse_matches: false,
 2242            workspace: None,
 2243            input_enabled: !is_minimap,
 2244            use_modal_editing: full_mode,
 2245            read_only: is_minimap,
 2246            use_autoclose: true,
 2247            use_auto_surround: true,
 2248            auto_replace_emoji_shortcode: false,
 2249            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2250            leader_id: None,
 2251            remote_id: None,
 2252            hover_state: HoverState::default(),
 2253            pending_mouse_down: None,
 2254            hovered_link_state: None,
 2255            edit_prediction_provider: None,
 2256            active_edit_prediction: None,
 2257            stale_edit_prediction_in_menu: None,
 2258            edit_prediction_preview: EditPredictionPreview::Inactive {
 2259                released_too_fast: false,
 2260            },
 2261            inline_diagnostics_enabled: full_mode,
 2262            diagnostics_enabled: full_mode,
 2263            word_completions_enabled: full_mode,
 2264            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2265            gutter_hovered: false,
 2266            pixel_position_of_newest_cursor: None,
 2267            last_bounds: None,
 2268            last_position_map: None,
 2269            expect_bounds_change: None,
 2270            gutter_dimensions: GutterDimensions::default(),
 2271            style: None,
 2272            show_cursor_names: false,
 2273            hovered_cursors: HashMap::default(),
 2274            next_editor_action_id: EditorActionId::default(),
 2275            editor_actions: Rc::default(),
 2276            edit_predictions_hidden_for_vim_mode: false,
 2277            show_edit_predictions_override: None,
 2278            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2279            edit_prediction_settings: EditPredictionSettings::Disabled,
 2280            edit_prediction_indent_conflict: false,
 2281            edit_prediction_requires_modifier_in_indent_conflict: true,
 2282            custom_context_menu: None,
 2283            show_git_blame_gutter: false,
 2284            show_git_blame_inline: false,
 2285            show_selection_menu: None,
 2286            show_git_blame_inline_delay_task: None,
 2287            git_blame_inline_enabled: full_mode
 2288                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2289            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2290            buffer_serialization: is_minimap.not().then(|| {
 2291                BufferSerialization::new(
 2292                    ProjectSettings::get_global(cx)
 2293                        .session
 2294                        .restore_unsaved_buffers,
 2295                )
 2296            }),
 2297            blame: None,
 2298            blame_subscription: None,
 2299            tasks: BTreeMap::default(),
 2300
 2301            breakpoint_store,
 2302            gutter_breakpoint_indicator: (None, None),
 2303            hovered_diff_hunk_row: None,
 2304            _subscriptions: (!is_minimap)
 2305                .then(|| {
 2306                    vec![
 2307                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2308                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2309                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2310                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2311                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2312                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2313                        cx.observe_window_activation(window, |editor, window, cx| {
 2314                            let active = window.is_window_active();
 2315                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2316                                if active {
 2317                                    blink_manager.enable(cx);
 2318                                } else {
 2319                                    blink_manager.disable(cx);
 2320                                }
 2321                            });
 2322                            if active {
 2323                                editor.show_mouse_cursor(cx);
 2324                            }
 2325                        }),
 2326                    ]
 2327                })
 2328                .unwrap_or_default(),
 2329            tasks_update_task: None,
 2330            pull_diagnostics_task: Task::ready(()),
 2331            pull_diagnostics_background_task: Task::ready(()),
 2332            colors: None,
 2333            refresh_colors_task: Task::ready(()),
 2334            inlay_hints: None,
 2335            next_color_inlay_id: 0,
 2336            post_scroll_update: Task::ready(()),
 2337            linked_edit_ranges: Default::default(),
 2338            in_project_search: false,
 2339            previous_search_ranges: None,
 2340            breadcrumb_header: None,
 2341            focused_block: None,
 2342            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2343            addons: HashMap::default(),
 2344            registered_buffers: HashMap::default(),
 2345            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2346            selection_mark_mode: false,
 2347            toggle_fold_multiple_buffers: Task::ready(()),
 2348            serialize_selections: Task::ready(()),
 2349            serialize_folds: Task::ready(()),
 2350            text_style_refinement: None,
 2351            load_diff_task: load_uncommitted_diff,
 2352            temporary_diff_override: false,
 2353            mouse_cursor_hidden: false,
 2354            minimap: None,
 2355            hide_mouse_mode: EditorSettings::get_global(cx)
 2356                .hide_mouse
 2357                .unwrap_or_default(),
 2358            change_list: ChangeList::new(),
 2359            mode,
 2360            selection_drag_state: SelectionDragState::None,
 2361            folding_newlines: Task::ready(()),
 2362            lookup_key: None,
 2363            select_next_is_case_sensitive: None,
 2364            applicable_language_settings: HashMap::default(),
 2365            accent_data: None,
 2366            fetched_tree_sitter_chunks: HashMap::default(),
 2367            use_base_text_line_numbers: false,
 2368        };
 2369
 2370        if is_minimap {
 2371            return editor;
 2372        }
 2373
 2374        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2375        editor.accent_data = editor.fetch_accent_data(cx);
 2376
 2377        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2378            editor
 2379                ._subscriptions
 2380                .push(cx.observe(breakpoints, |_, _, cx| {
 2381                    cx.notify();
 2382                }));
 2383        }
 2384        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2385        editor._subscriptions.extend(project_subscriptions);
 2386
 2387        editor._subscriptions.push(cx.subscribe_in(
 2388            &cx.entity(),
 2389            window,
 2390            |editor, _, e: &EditorEvent, window, cx| match e {
 2391                EditorEvent::ScrollPositionChanged { local, .. } => {
 2392                    if *local {
 2393                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2394                        editor.inline_blame_popover.take();
 2395                        let new_anchor = editor.scroll_manager.anchor();
 2396                        let snapshot = editor.snapshot(window, cx);
 2397                        editor.update_restoration_data(cx, move |data| {
 2398                            data.scroll_position = (
 2399                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2400                                new_anchor.offset,
 2401                            );
 2402                        });
 2403
 2404                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2405                            cx.background_executor()
 2406                                .timer(Duration::from_millis(50))
 2407                                .await;
 2408                            editor
 2409                                .update_in(cx, |editor, window, cx| {
 2410                                    editor.register_visible_buffers(cx);
 2411                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2412                                    editor.refresh_inlay_hints(
 2413                                        InlayHintRefreshReason::NewLinesShown,
 2414                                        cx,
 2415                                    );
 2416                                    editor.colorize_brackets(false, cx);
 2417                                })
 2418                                .ok();
 2419                        });
 2420                    }
 2421                }
 2422                EditorEvent::Edited { .. } => {
 2423                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2424                        .map(|vim_mode| vim_mode.0)
 2425                        .unwrap_or(false);
 2426                    if !vim_mode {
 2427                        let display_map = editor.display_snapshot(cx);
 2428                        let selections = editor.selections.all_adjusted_display(&display_map);
 2429                        let pop_state = editor
 2430                            .change_list
 2431                            .last()
 2432                            .map(|previous| {
 2433                                previous.len() == selections.len()
 2434                                    && previous.iter().enumerate().all(|(ix, p)| {
 2435                                        p.to_display_point(&display_map).row()
 2436                                            == selections[ix].head().row()
 2437                                    })
 2438                            })
 2439                            .unwrap_or(false);
 2440                        let new_positions = selections
 2441                            .into_iter()
 2442                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2443                            .collect();
 2444                        editor
 2445                            .change_list
 2446                            .push_to_change_list(pop_state, new_positions);
 2447                    }
 2448                }
 2449                _ => (),
 2450            },
 2451        ));
 2452
 2453        if let Some(dap_store) = editor
 2454            .project
 2455            .as_ref()
 2456            .map(|project| project.read(cx).dap_store())
 2457        {
 2458            let weak_editor = cx.weak_entity();
 2459
 2460            editor
 2461                ._subscriptions
 2462                .push(
 2463                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2464                        let session_entity = cx.entity();
 2465                        weak_editor
 2466                            .update(cx, |editor, cx| {
 2467                                editor._subscriptions.push(
 2468                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2469                                );
 2470                            })
 2471                            .ok();
 2472                    }),
 2473                );
 2474
 2475            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2476                editor
 2477                    ._subscriptions
 2478                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2479            }
 2480        }
 2481
 2482        // skip adding the initial selection to selection history
 2483        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2484        editor.end_selection(window, cx);
 2485        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2486
 2487        editor.scroll_manager.show_scrollbars(window, cx);
 2488        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2489
 2490        if full_mode {
 2491            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2492            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2493
 2494            if editor.git_blame_inline_enabled {
 2495                editor.start_git_blame_inline(false, window, cx);
 2496            }
 2497
 2498            editor.go_to_active_debug_line(window, cx);
 2499
 2500            editor.minimap =
 2501                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2502            editor.colors = Some(LspColorData::new(cx));
 2503            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2504
 2505            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2506                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2507            }
 2508            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2509        }
 2510
 2511        editor
 2512    }
 2513
 2514    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2515        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2516    }
 2517
 2518    pub fn deploy_mouse_context_menu(
 2519        &mut self,
 2520        position: gpui::Point<Pixels>,
 2521        context_menu: Entity<ContextMenu>,
 2522        window: &mut Window,
 2523        cx: &mut Context<Self>,
 2524    ) {
 2525        self.mouse_context_menu = Some(MouseContextMenu::new(
 2526            self,
 2527            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2528            context_menu,
 2529            window,
 2530            cx,
 2531        ));
 2532    }
 2533
 2534    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2535        self.mouse_context_menu
 2536            .as_ref()
 2537            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2538    }
 2539
 2540    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2541        if self
 2542            .selections
 2543            .pending_anchor()
 2544            .is_some_and(|pending_selection| {
 2545                let snapshot = self.buffer().read(cx).snapshot(cx);
 2546                pending_selection.range().includes(range, &snapshot)
 2547            })
 2548        {
 2549            return true;
 2550        }
 2551
 2552        self.selections
 2553            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2554            .into_iter()
 2555            .any(|selection| {
 2556                // This is needed to cover a corner case, if we just check for an existing
 2557                // selection in the fold range, having a cursor at the start of the fold
 2558                // marks it as selected. Non-empty selections don't cause this.
 2559                let length = selection.end - selection.start;
 2560                length > 0
 2561            })
 2562    }
 2563
 2564    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2565        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2566    }
 2567
 2568    fn key_context_internal(
 2569        &self,
 2570        has_active_edit_prediction: bool,
 2571        window: &mut Window,
 2572        cx: &mut App,
 2573    ) -> KeyContext {
 2574        let mut key_context = KeyContext::new_with_defaults();
 2575        key_context.add("Editor");
 2576        let mode = match self.mode {
 2577            EditorMode::SingleLine => "single_line",
 2578            EditorMode::AutoHeight { .. } => "auto_height",
 2579            EditorMode::Minimap { .. } => "minimap",
 2580            EditorMode::Full { .. } => "full",
 2581        };
 2582
 2583        if EditorSettings::jupyter_enabled(cx) {
 2584            key_context.add("jupyter");
 2585        }
 2586
 2587        key_context.set("mode", mode);
 2588        if self.pending_rename.is_some() {
 2589            key_context.add("renaming");
 2590        }
 2591
 2592        if let Some(snippet_stack) = self.snippet_stack.last() {
 2593            key_context.add("in_snippet");
 2594
 2595            if snippet_stack.active_index > 0 {
 2596                key_context.add("has_previous_tabstop");
 2597            }
 2598
 2599            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2600                key_context.add("has_next_tabstop");
 2601            }
 2602        }
 2603
 2604        match self.context_menu.borrow().as_ref() {
 2605            Some(CodeContextMenu::Completions(menu)) => {
 2606                if menu.visible() {
 2607                    key_context.add("menu");
 2608                    key_context.add("showing_completions");
 2609                }
 2610            }
 2611            Some(CodeContextMenu::CodeActions(menu)) => {
 2612                if menu.visible() {
 2613                    key_context.add("menu");
 2614                    key_context.add("showing_code_actions")
 2615                }
 2616            }
 2617            None => {}
 2618        }
 2619
 2620        if self.signature_help_state.has_multiple_signatures() {
 2621            key_context.add("showing_signature_help");
 2622        }
 2623
 2624        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2625        if !self.focus_handle(cx).contains_focused(window, cx)
 2626            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2627        {
 2628            for addon in self.addons.values() {
 2629                addon.extend_key_context(&mut key_context, cx)
 2630            }
 2631        }
 2632
 2633        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2634            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2635                Some(
 2636                    file.full_path(cx)
 2637                        .extension()?
 2638                        .to_string_lossy()
 2639                        .into_owned(),
 2640                )
 2641            }) {
 2642                key_context.set("extension", extension);
 2643            }
 2644        } else {
 2645            key_context.add("multibuffer");
 2646        }
 2647
 2648        if has_active_edit_prediction {
 2649            if self.edit_prediction_in_conflict() {
 2650                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2651            } else {
 2652                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2653                key_context.add("copilot_suggestion");
 2654            }
 2655        }
 2656
 2657        if self.selection_mark_mode {
 2658            key_context.add("selection_mode");
 2659        }
 2660
 2661        let disjoint = self.selections.disjoint_anchors();
 2662        let snapshot = self.snapshot(window, cx);
 2663        let snapshot = snapshot.buffer_snapshot();
 2664        if self.mode == EditorMode::SingleLine
 2665            && let [selection] = disjoint
 2666            && selection.start == selection.end
 2667            && selection.end.to_offset(snapshot) == snapshot.len()
 2668        {
 2669            key_context.add("end_of_input");
 2670        }
 2671
 2672        if self.has_any_expanded_diff_hunks(cx) {
 2673            key_context.add("diffs_expanded");
 2674        }
 2675
 2676        key_context
 2677    }
 2678
 2679    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2680        self.last_bounds.as_ref()
 2681    }
 2682
 2683    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2684        if self.mouse_cursor_hidden {
 2685            self.mouse_cursor_hidden = false;
 2686            cx.notify();
 2687        }
 2688    }
 2689
 2690    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2691        let hide_mouse_cursor = match origin {
 2692            HideMouseCursorOrigin::TypingAction => {
 2693                matches!(
 2694                    self.hide_mouse_mode,
 2695                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2696                )
 2697            }
 2698            HideMouseCursorOrigin::MovementAction => {
 2699                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2700            }
 2701        };
 2702        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2703            self.mouse_cursor_hidden = hide_mouse_cursor;
 2704            cx.notify();
 2705        }
 2706    }
 2707
 2708    pub fn edit_prediction_in_conflict(&self) -> bool {
 2709        if !self.show_edit_predictions_in_menu() {
 2710            return false;
 2711        }
 2712
 2713        let showing_completions = self
 2714            .context_menu
 2715            .borrow()
 2716            .as_ref()
 2717            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2718
 2719        showing_completions
 2720            || self.edit_prediction_requires_modifier()
 2721            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2722            // bindings to insert tab characters.
 2723            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2724    }
 2725
 2726    pub fn accept_edit_prediction_keybind(
 2727        &self,
 2728        accept_partial: bool,
 2729        window: &mut Window,
 2730        cx: &mut App,
 2731    ) -> AcceptEditPredictionBinding {
 2732        let key_context = self.key_context_internal(true, window, cx);
 2733        let in_conflict = self.edit_prediction_in_conflict();
 2734
 2735        let bindings = if accept_partial {
 2736            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2737        } else {
 2738            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2739        };
 2740
 2741        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2742        // just the first one.
 2743        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2744            !in_conflict
 2745                || binding
 2746                    .keystrokes()
 2747                    .first()
 2748                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2749        }))
 2750    }
 2751
 2752    pub fn new_file(
 2753        workspace: &mut Workspace,
 2754        _: &workspace::NewFile,
 2755        window: &mut Window,
 2756        cx: &mut Context<Workspace>,
 2757    ) {
 2758        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2759            "Failed to create buffer",
 2760            window,
 2761            cx,
 2762            |e, _, _| match e.error_code() {
 2763                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2764                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2765                e.error_tag("required").unwrap_or("the latest version")
 2766            )),
 2767                _ => None,
 2768            },
 2769        );
 2770    }
 2771
 2772    pub fn new_in_workspace(
 2773        workspace: &mut Workspace,
 2774        window: &mut Window,
 2775        cx: &mut Context<Workspace>,
 2776    ) -> Task<Result<Entity<Editor>>> {
 2777        let project = workspace.project().clone();
 2778        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2779
 2780        cx.spawn_in(window, async move |workspace, cx| {
 2781            let buffer = create.await?;
 2782            workspace.update_in(cx, |workspace, window, cx| {
 2783                let editor =
 2784                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2785                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2786                editor
 2787            })
 2788        })
 2789    }
 2790
 2791    fn new_file_vertical(
 2792        workspace: &mut Workspace,
 2793        _: &workspace::NewFileSplitVertical,
 2794        window: &mut Window,
 2795        cx: &mut Context<Workspace>,
 2796    ) {
 2797        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2798    }
 2799
 2800    fn new_file_horizontal(
 2801        workspace: &mut Workspace,
 2802        _: &workspace::NewFileSplitHorizontal,
 2803        window: &mut Window,
 2804        cx: &mut Context<Workspace>,
 2805    ) {
 2806        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2807    }
 2808
 2809    fn new_file_split(
 2810        workspace: &mut Workspace,
 2811        action: &workspace::NewFileSplit,
 2812        window: &mut Window,
 2813        cx: &mut Context<Workspace>,
 2814    ) {
 2815        Self::new_file_in_direction(workspace, action.0, window, cx)
 2816    }
 2817
 2818    fn new_file_in_direction(
 2819        workspace: &mut Workspace,
 2820        direction: SplitDirection,
 2821        window: &mut Window,
 2822        cx: &mut Context<Workspace>,
 2823    ) {
 2824        let project = workspace.project().clone();
 2825        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2826
 2827        cx.spawn_in(window, async move |workspace, cx| {
 2828            let buffer = create.await?;
 2829            workspace.update_in(cx, move |workspace, window, cx| {
 2830                workspace.split_item(
 2831                    direction,
 2832                    Box::new(
 2833                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2834                    ),
 2835                    window,
 2836                    cx,
 2837                )
 2838            })?;
 2839            anyhow::Ok(())
 2840        })
 2841        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2842            match e.error_code() {
 2843                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2844                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2845                e.error_tag("required").unwrap_or("the latest version")
 2846            )),
 2847                _ => None,
 2848            }
 2849        });
 2850    }
 2851
 2852    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2853        self.leader_id
 2854    }
 2855
 2856    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2857        &self.buffer
 2858    }
 2859
 2860    pub fn project(&self) -> Option<&Entity<Project>> {
 2861        self.project.as_ref()
 2862    }
 2863
 2864    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2865        self.workspace.as_ref()?.0.upgrade()
 2866    }
 2867
 2868    /// Returns the workspace serialization ID if this editor should be serialized.
 2869    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2870        self.workspace
 2871            .as_ref()
 2872            .filter(|_| self.should_serialize_buffer())
 2873            .and_then(|workspace| workspace.1)
 2874    }
 2875
 2876    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2877        self.buffer().read(cx).title(cx)
 2878    }
 2879
 2880    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2881        let git_blame_gutter_max_author_length = self
 2882            .render_git_blame_gutter(cx)
 2883            .then(|| {
 2884                if let Some(blame) = self.blame.as_ref() {
 2885                    let max_author_length =
 2886                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2887                    Some(max_author_length)
 2888                } else {
 2889                    None
 2890                }
 2891            })
 2892            .flatten();
 2893
 2894        EditorSnapshot {
 2895            mode: self.mode.clone(),
 2896            show_gutter: self.show_gutter,
 2897            show_line_numbers: self.show_line_numbers,
 2898            show_git_diff_gutter: self.show_git_diff_gutter,
 2899            show_code_actions: self.show_code_actions,
 2900            show_runnables: self.show_runnables,
 2901            show_breakpoints: self.show_breakpoints,
 2902            git_blame_gutter_max_author_length,
 2903            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2904            placeholder_display_snapshot: self
 2905                .placeholder_display_map
 2906                .as_ref()
 2907                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2908            scroll_anchor: self.scroll_manager.anchor(),
 2909            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2910            is_focused: self.focus_handle.is_focused(window),
 2911            current_line_highlight: self
 2912                .current_line_highlight
 2913                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2914            gutter_hovered: self.gutter_hovered,
 2915        }
 2916    }
 2917
 2918    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2919        self.buffer.read(cx).language_at(point, cx)
 2920    }
 2921
 2922    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2923        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2924    }
 2925
 2926    pub fn active_excerpt(
 2927        &self,
 2928        cx: &App,
 2929    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2930        self.buffer
 2931            .read(cx)
 2932            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2933    }
 2934
 2935    pub fn mode(&self) -> &EditorMode {
 2936        &self.mode
 2937    }
 2938
 2939    pub fn set_mode(&mut self, mode: EditorMode) {
 2940        self.mode = mode;
 2941    }
 2942
 2943    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2944        self.collaboration_hub.as_deref()
 2945    }
 2946
 2947    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2948        self.collaboration_hub = Some(hub);
 2949    }
 2950
 2951    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2952        self.in_project_search = in_project_search;
 2953    }
 2954
 2955    pub fn set_custom_context_menu(
 2956        &mut self,
 2957        f: impl 'static
 2958        + Fn(
 2959            &mut Self,
 2960            DisplayPoint,
 2961            &mut Window,
 2962            &mut Context<Self>,
 2963        ) -> Option<Entity<ui::ContextMenu>>,
 2964    ) {
 2965        self.custom_context_menu = Some(Box::new(f))
 2966    }
 2967
 2968    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2969        self.completion_provider = provider;
 2970    }
 2971
 2972    #[cfg(any(test, feature = "test-support"))]
 2973    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2974        self.completion_provider.clone()
 2975    }
 2976
 2977    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2978        self.semantics_provider.clone()
 2979    }
 2980
 2981    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2982        self.semantics_provider = provider;
 2983    }
 2984
 2985    pub fn set_edit_prediction_provider<T>(
 2986        &mut self,
 2987        provider: Option<Entity<T>>,
 2988        window: &mut Window,
 2989        cx: &mut Context<Self>,
 2990    ) where
 2991        T: EditPredictionProvider,
 2992    {
 2993        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2994            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2995                if this.focus_handle.is_focused(window) {
 2996                    this.update_visible_edit_prediction(window, cx);
 2997                }
 2998            }),
 2999            provider: Arc::new(provider),
 3000        });
 3001        self.update_edit_prediction_settings(cx);
 3002        self.refresh_edit_prediction(false, false, window, cx);
 3003    }
 3004
 3005    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3006        self.placeholder_display_map
 3007            .as_ref()
 3008            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3009    }
 3010
 3011    pub fn set_placeholder_text(
 3012        &mut self,
 3013        placeholder_text: &str,
 3014        window: &mut Window,
 3015        cx: &mut Context<Self>,
 3016    ) {
 3017        let multibuffer = cx
 3018            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3019
 3020        let style = window.text_style();
 3021
 3022        self.placeholder_display_map = Some(cx.new(|cx| {
 3023            DisplayMap::new(
 3024                multibuffer,
 3025                style.font(),
 3026                style.font_size.to_pixels(window.rem_size()),
 3027                None,
 3028                FILE_HEADER_HEIGHT,
 3029                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3030                Default::default(),
 3031                DiagnosticSeverity::Off,
 3032                cx,
 3033            )
 3034        }));
 3035        cx.notify();
 3036    }
 3037
 3038    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3039        self.cursor_shape = cursor_shape;
 3040
 3041        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3042        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3043
 3044        cx.notify();
 3045    }
 3046
 3047    pub fn cursor_shape(&self) -> CursorShape {
 3048        self.cursor_shape
 3049    }
 3050
 3051    pub fn set_current_line_highlight(
 3052        &mut self,
 3053        current_line_highlight: Option<CurrentLineHighlight>,
 3054    ) {
 3055        self.current_line_highlight = current_line_highlight;
 3056    }
 3057
 3058    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3059        self.collapse_matches = collapse_matches;
 3060    }
 3061
 3062    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3063        if self.collapse_matches {
 3064            return range.start..range.start;
 3065        }
 3066        range.clone()
 3067    }
 3068
 3069    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3070        self.display_map.read(cx).clip_at_line_ends
 3071    }
 3072
 3073    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3074        if self.display_map.read(cx).clip_at_line_ends != clip {
 3075            self.display_map
 3076                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3077        }
 3078    }
 3079
 3080    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3081        self.input_enabled = input_enabled;
 3082    }
 3083
 3084    pub fn set_edit_predictions_hidden_for_vim_mode(
 3085        &mut self,
 3086        hidden: bool,
 3087        window: &mut Window,
 3088        cx: &mut Context<Self>,
 3089    ) {
 3090        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3091            self.edit_predictions_hidden_for_vim_mode = hidden;
 3092            if hidden {
 3093                self.update_visible_edit_prediction(window, cx);
 3094            } else {
 3095                self.refresh_edit_prediction(true, false, window, cx);
 3096            }
 3097        }
 3098    }
 3099
 3100    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3101        self.menu_edit_predictions_policy = value;
 3102    }
 3103
 3104    pub fn set_autoindent(&mut self, autoindent: bool) {
 3105        if autoindent {
 3106            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3107        } else {
 3108            self.autoindent_mode = None;
 3109        }
 3110    }
 3111
 3112    pub fn read_only(&self, cx: &App) -> bool {
 3113        self.read_only || self.buffer.read(cx).read_only()
 3114    }
 3115
 3116    pub fn set_read_only(&mut self, read_only: bool) {
 3117        self.read_only = read_only;
 3118    }
 3119
 3120    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3121        self.use_autoclose = autoclose;
 3122    }
 3123
 3124    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3125        self.use_auto_surround = auto_surround;
 3126    }
 3127
 3128    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3129        self.auto_replace_emoji_shortcode = auto_replace;
 3130    }
 3131
 3132    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3133        self.buffer_serialization = should_serialize.then(|| {
 3134            BufferSerialization::new(
 3135                ProjectSettings::get_global(cx)
 3136                    .session
 3137                    .restore_unsaved_buffers,
 3138            )
 3139        })
 3140    }
 3141
 3142    fn should_serialize_buffer(&self) -> bool {
 3143        self.buffer_serialization.is_some()
 3144    }
 3145
 3146    pub fn toggle_edit_predictions(
 3147        &mut self,
 3148        _: &ToggleEditPrediction,
 3149        window: &mut Window,
 3150        cx: &mut Context<Self>,
 3151    ) {
 3152        if self.show_edit_predictions_override.is_some() {
 3153            self.set_show_edit_predictions(None, window, cx);
 3154        } else {
 3155            let show_edit_predictions = !self.edit_predictions_enabled();
 3156            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3157        }
 3158    }
 3159
 3160    pub fn set_show_edit_predictions(
 3161        &mut self,
 3162        show_edit_predictions: Option<bool>,
 3163        window: &mut Window,
 3164        cx: &mut Context<Self>,
 3165    ) {
 3166        self.show_edit_predictions_override = show_edit_predictions;
 3167        self.update_edit_prediction_settings(cx);
 3168
 3169        if let Some(false) = show_edit_predictions {
 3170            self.discard_edit_prediction(false, cx);
 3171        } else {
 3172            self.refresh_edit_prediction(false, true, window, cx);
 3173        }
 3174    }
 3175
 3176    fn edit_predictions_disabled_in_scope(
 3177        &self,
 3178        buffer: &Entity<Buffer>,
 3179        buffer_position: language::Anchor,
 3180        cx: &App,
 3181    ) -> bool {
 3182        let snapshot = buffer.read(cx).snapshot();
 3183        let settings = snapshot.settings_at(buffer_position, cx);
 3184
 3185        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3186            return false;
 3187        };
 3188
 3189        scope.override_name().is_some_and(|scope_name| {
 3190            settings
 3191                .edit_predictions_disabled_in
 3192                .iter()
 3193                .any(|s| s == scope_name)
 3194        })
 3195    }
 3196
 3197    pub fn set_use_modal_editing(&mut self, to: bool) {
 3198        self.use_modal_editing = to;
 3199    }
 3200
 3201    pub fn use_modal_editing(&self) -> bool {
 3202        self.use_modal_editing
 3203    }
 3204
 3205    fn selections_did_change(
 3206        &mut self,
 3207        local: bool,
 3208        old_cursor_position: &Anchor,
 3209        effects: SelectionEffects,
 3210        window: &mut Window,
 3211        cx: &mut Context<Self>,
 3212    ) {
 3213        window.invalidate_character_coordinates();
 3214
 3215        // Copy selections to primary selection buffer
 3216        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3217        if local {
 3218            let selections = self
 3219                .selections
 3220                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3221            let buffer_handle = self.buffer.read(cx).read(cx);
 3222
 3223            let mut text = String::new();
 3224            for (index, selection) in selections.iter().enumerate() {
 3225                let text_for_selection = buffer_handle
 3226                    .text_for_range(selection.start..selection.end)
 3227                    .collect::<String>();
 3228
 3229                text.push_str(&text_for_selection);
 3230                if index != selections.len() - 1 {
 3231                    text.push('\n');
 3232                }
 3233            }
 3234
 3235            if !text.is_empty() {
 3236                cx.write_to_primary(ClipboardItem::new_string(text));
 3237            }
 3238        }
 3239
 3240        let selection_anchors = self.selections.disjoint_anchors_arc();
 3241
 3242        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3243            self.buffer.update(cx, |buffer, cx| {
 3244                buffer.set_active_selections(
 3245                    &selection_anchors,
 3246                    self.selections.line_mode(),
 3247                    self.cursor_shape,
 3248                    cx,
 3249                )
 3250            });
 3251        }
 3252        let display_map = self
 3253            .display_map
 3254            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3255        let buffer = display_map.buffer_snapshot();
 3256        if self.selections.count() == 1 {
 3257            self.add_selections_state = None;
 3258        }
 3259        self.select_next_state = None;
 3260        self.select_prev_state = None;
 3261        self.select_syntax_node_history.try_clear();
 3262        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3263        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3264        self.take_rename(false, window, cx);
 3265
 3266        let newest_selection = self.selections.newest_anchor();
 3267        let new_cursor_position = newest_selection.head();
 3268        let selection_start = newest_selection.start;
 3269
 3270        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3271            self.push_to_nav_history(
 3272                *old_cursor_position,
 3273                Some(new_cursor_position.to_point(buffer)),
 3274                false,
 3275                effects.nav_history == Some(true),
 3276                cx,
 3277            );
 3278        }
 3279
 3280        if local {
 3281            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3282                self.register_buffer(buffer_id, cx);
 3283            }
 3284
 3285            let mut context_menu = self.context_menu.borrow_mut();
 3286            let completion_menu = match context_menu.as_ref() {
 3287                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3288                Some(CodeContextMenu::CodeActions(_)) => {
 3289                    *context_menu = None;
 3290                    None
 3291                }
 3292                None => None,
 3293            };
 3294            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3295            drop(context_menu);
 3296
 3297            if effects.completions
 3298                && let Some(completion_position) = completion_position
 3299            {
 3300                let start_offset = selection_start.to_offset(buffer);
 3301                let position_matches = start_offset == completion_position.to_offset(buffer);
 3302                let continue_showing = if position_matches {
 3303                    if self.snippet_stack.is_empty() {
 3304                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3305                            == Some(CharKind::Word)
 3306                    } else {
 3307                        // Snippet choices can be shown even when the cursor is in whitespace.
 3308                        // Dismissing the menu with actions like backspace is handled by
 3309                        // invalidation regions.
 3310                        true
 3311                    }
 3312                } else {
 3313                    false
 3314                };
 3315
 3316                if continue_showing {
 3317                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3318                } else {
 3319                    self.hide_context_menu(window, cx);
 3320                }
 3321            }
 3322
 3323            hide_hover(self, cx);
 3324
 3325            if old_cursor_position.to_display_point(&display_map).row()
 3326                != new_cursor_position.to_display_point(&display_map).row()
 3327            {
 3328                self.available_code_actions.take();
 3329            }
 3330            self.refresh_code_actions(window, cx);
 3331            self.refresh_document_highlights(cx);
 3332            refresh_linked_ranges(self, window, cx);
 3333
 3334            self.refresh_selected_text_highlights(false, window, cx);
 3335            self.refresh_matching_bracket_highlights(window, cx);
 3336            self.update_visible_edit_prediction(window, cx);
 3337            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3338            self.inline_blame_popover.take();
 3339            if self.git_blame_inline_enabled {
 3340                self.start_inline_blame_timer(window, cx);
 3341            }
 3342        }
 3343
 3344        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3345        cx.emit(EditorEvent::SelectionsChanged { local });
 3346
 3347        let selections = &self.selections.disjoint_anchors_arc();
 3348        if selections.len() == 1 {
 3349            cx.emit(SearchEvent::ActiveMatchChanged)
 3350        }
 3351        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3352            let inmemory_selections = selections
 3353                .iter()
 3354                .map(|s| {
 3355                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3356                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3357                })
 3358                .collect();
 3359            self.update_restoration_data(cx, |data| {
 3360                data.selections = inmemory_selections;
 3361            });
 3362
 3363            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3364                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3365            {
 3366                let snapshot = self.buffer().read(cx).snapshot(cx);
 3367                let selections = selections.clone();
 3368                let background_executor = cx.background_executor().clone();
 3369                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3370                self.serialize_selections = cx.background_spawn(async move {
 3371                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3372                    let db_selections = selections
 3373                        .iter()
 3374                        .map(|selection| {
 3375                            (
 3376                                selection.start.to_offset(&snapshot).0,
 3377                                selection.end.to_offset(&snapshot).0,
 3378                            )
 3379                        })
 3380                        .collect();
 3381
 3382                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3383                        .await
 3384                        .with_context(|| {
 3385                            format!(
 3386                                "persisting editor selections for editor {editor_id}, \
 3387                                workspace {workspace_id:?}"
 3388                            )
 3389                        })
 3390                        .log_err();
 3391                });
 3392            }
 3393        }
 3394
 3395        cx.notify();
 3396    }
 3397
 3398    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3399        use text::ToOffset as _;
 3400        use text::ToPoint as _;
 3401
 3402        if self.mode.is_minimap()
 3403            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3404        {
 3405            return;
 3406        }
 3407
 3408        if !self.buffer().read(cx).is_singleton() {
 3409            return;
 3410        }
 3411
 3412        let display_snapshot = self
 3413            .display_map
 3414            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3415        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3416            return;
 3417        };
 3418        let inmemory_folds = display_snapshot
 3419            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3420            .map(|fold| {
 3421                fold.range.start.text_anchor.to_point(&snapshot)
 3422                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3423            })
 3424            .collect();
 3425        self.update_restoration_data(cx, |data| {
 3426            data.folds = inmemory_folds;
 3427        });
 3428
 3429        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3430            return;
 3431        };
 3432        let background_executor = cx.background_executor().clone();
 3433        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3434        let db_folds = display_snapshot
 3435            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3436            .map(|fold| {
 3437                (
 3438                    fold.range.start.text_anchor.to_offset(&snapshot),
 3439                    fold.range.end.text_anchor.to_offset(&snapshot),
 3440                )
 3441            })
 3442            .collect();
 3443        self.serialize_folds = cx.background_spawn(async move {
 3444            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3445            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3446                .await
 3447                .with_context(|| {
 3448                    format!(
 3449                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3450                    )
 3451                })
 3452                .log_err();
 3453        });
 3454    }
 3455
 3456    pub fn sync_selections(
 3457        &mut self,
 3458        other: Entity<Editor>,
 3459        cx: &mut Context<Self>,
 3460    ) -> gpui::Subscription {
 3461        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3462        if !other_selections.is_empty() {
 3463            self.selections
 3464                .change_with(&self.display_snapshot(cx), |selections| {
 3465                    selections.select_anchors(other_selections);
 3466                });
 3467        }
 3468
 3469        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3470            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3471                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3472                if other_selections.is_empty() {
 3473                    return;
 3474                }
 3475                let snapshot = this.display_snapshot(cx);
 3476                this.selections.change_with(&snapshot, |selections| {
 3477                    selections.select_anchors(other_selections);
 3478                });
 3479            }
 3480        });
 3481
 3482        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3483            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3484                let these_selections = this.selections.disjoint_anchors().to_vec();
 3485                if these_selections.is_empty() {
 3486                    return;
 3487                }
 3488                other.update(cx, |other_editor, cx| {
 3489                    let snapshot = other_editor.display_snapshot(cx);
 3490                    other_editor
 3491                        .selections
 3492                        .change_with(&snapshot, |selections| {
 3493                            selections.select_anchors(these_selections);
 3494                        })
 3495                });
 3496            }
 3497        });
 3498
 3499        Subscription::join(other_subscription, this_subscription)
 3500    }
 3501
 3502    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3503        if self.buffer().read(cx).is_singleton() {
 3504            return;
 3505        }
 3506        let snapshot = self.buffer.read(cx).snapshot(cx);
 3507        let buffer_ids: HashSet<BufferId> = self
 3508            .selections
 3509            .disjoint_anchor_ranges()
 3510            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3511            .collect();
 3512        for buffer_id in buffer_ids {
 3513            self.unfold_buffer(buffer_id, cx);
 3514        }
 3515    }
 3516
 3517    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3518    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3519    /// effects of selection change occur at the end of the transaction.
 3520    pub fn change_selections<R>(
 3521        &mut self,
 3522        effects: SelectionEffects,
 3523        window: &mut Window,
 3524        cx: &mut Context<Self>,
 3525        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3526    ) -> R {
 3527        let snapshot = self.display_snapshot(cx);
 3528        if let Some(state) = &mut self.deferred_selection_effects_state {
 3529            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3530            state.effects.completions = effects.completions;
 3531            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3532            let (changed, result) = self.selections.change_with(&snapshot, change);
 3533            state.changed |= changed;
 3534            return result;
 3535        }
 3536        let mut state = DeferredSelectionEffectsState {
 3537            changed: false,
 3538            effects,
 3539            old_cursor_position: self.selections.newest_anchor().head(),
 3540            history_entry: SelectionHistoryEntry {
 3541                selections: self.selections.disjoint_anchors_arc(),
 3542                select_next_state: self.select_next_state.clone(),
 3543                select_prev_state: self.select_prev_state.clone(),
 3544                add_selections_state: self.add_selections_state.clone(),
 3545            },
 3546        };
 3547        let (changed, result) = self.selections.change_with(&snapshot, change);
 3548        state.changed = state.changed || changed;
 3549        if self.defer_selection_effects {
 3550            self.deferred_selection_effects_state = Some(state);
 3551        } else {
 3552            self.apply_selection_effects(state, window, cx);
 3553        }
 3554        result
 3555    }
 3556
 3557    /// Defers the effects of selection change, so that the effects of multiple calls to
 3558    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3559    /// to selection history and the state of popovers based on selection position aren't
 3560    /// erroneously updated.
 3561    pub fn with_selection_effects_deferred<R>(
 3562        &mut self,
 3563        window: &mut Window,
 3564        cx: &mut Context<Self>,
 3565        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3566    ) -> R {
 3567        let already_deferred = self.defer_selection_effects;
 3568        self.defer_selection_effects = true;
 3569        let result = update(self, window, cx);
 3570        if !already_deferred {
 3571            self.defer_selection_effects = false;
 3572            if let Some(state) = self.deferred_selection_effects_state.take() {
 3573                self.apply_selection_effects(state, window, cx);
 3574            }
 3575        }
 3576        result
 3577    }
 3578
 3579    fn apply_selection_effects(
 3580        &mut self,
 3581        state: DeferredSelectionEffectsState,
 3582        window: &mut Window,
 3583        cx: &mut Context<Self>,
 3584    ) {
 3585        if state.changed {
 3586            self.selection_history.push(state.history_entry);
 3587
 3588            if let Some(autoscroll) = state.effects.scroll {
 3589                self.request_autoscroll(autoscroll, cx);
 3590            }
 3591
 3592            let old_cursor_position = &state.old_cursor_position;
 3593
 3594            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3595
 3596            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3597                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3598            }
 3599        }
 3600    }
 3601
 3602    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3603    where
 3604        I: IntoIterator<Item = (Range<S>, T)>,
 3605        S: ToOffset,
 3606        T: Into<Arc<str>>,
 3607    {
 3608        if self.read_only(cx) {
 3609            return;
 3610        }
 3611
 3612        self.buffer
 3613            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3614    }
 3615
 3616    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3617    where
 3618        I: IntoIterator<Item = (Range<S>, T)>,
 3619        S: ToOffset,
 3620        T: Into<Arc<str>>,
 3621    {
 3622        if self.read_only(cx) {
 3623            return;
 3624        }
 3625
 3626        self.buffer.update(cx, |buffer, cx| {
 3627            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3628        });
 3629    }
 3630
 3631    pub fn edit_with_block_indent<I, S, T>(
 3632        &mut self,
 3633        edits: I,
 3634        original_indent_columns: Vec<Option<u32>>,
 3635        cx: &mut Context<Self>,
 3636    ) where
 3637        I: IntoIterator<Item = (Range<S>, T)>,
 3638        S: ToOffset,
 3639        T: Into<Arc<str>>,
 3640    {
 3641        if self.read_only(cx) {
 3642            return;
 3643        }
 3644
 3645        self.buffer.update(cx, |buffer, cx| {
 3646            buffer.edit(
 3647                edits,
 3648                Some(AutoindentMode::Block {
 3649                    original_indent_columns,
 3650                }),
 3651                cx,
 3652            )
 3653        });
 3654    }
 3655
 3656    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3657        self.hide_context_menu(window, cx);
 3658
 3659        match phase {
 3660            SelectPhase::Begin {
 3661                position,
 3662                add,
 3663                click_count,
 3664            } => self.begin_selection(position, add, click_count, window, cx),
 3665            SelectPhase::BeginColumnar {
 3666                position,
 3667                goal_column,
 3668                reset,
 3669                mode,
 3670            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3671            SelectPhase::Extend {
 3672                position,
 3673                click_count,
 3674            } => self.extend_selection(position, click_count, window, cx),
 3675            SelectPhase::Update {
 3676                position,
 3677                goal_column,
 3678                scroll_delta,
 3679            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3680            SelectPhase::End => self.end_selection(window, cx),
 3681        }
 3682    }
 3683
 3684    fn extend_selection(
 3685        &mut self,
 3686        position: DisplayPoint,
 3687        click_count: usize,
 3688        window: &mut Window,
 3689        cx: &mut Context<Self>,
 3690    ) {
 3691        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3692        let tail = self
 3693            .selections
 3694            .newest::<MultiBufferOffset>(&display_map)
 3695            .tail();
 3696        let click_count = click_count.max(match self.selections.select_mode() {
 3697            SelectMode::Character => 1,
 3698            SelectMode::Word(_) => 2,
 3699            SelectMode::Line(_) => 3,
 3700            SelectMode::All => 4,
 3701        });
 3702        self.begin_selection(position, false, click_count, window, cx);
 3703
 3704        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3705
 3706        let current_selection = match self.selections.select_mode() {
 3707            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3708            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3709        };
 3710
 3711        let mut pending_selection = self
 3712            .selections
 3713            .pending_anchor()
 3714            .cloned()
 3715            .expect("extend_selection not called with pending selection");
 3716
 3717        if pending_selection
 3718            .start
 3719            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3720            == Ordering::Greater
 3721        {
 3722            pending_selection.start = current_selection.start;
 3723        }
 3724        if pending_selection
 3725            .end
 3726            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3727            == Ordering::Less
 3728        {
 3729            pending_selection.end = current_selection.end;
 3730            pending_selection.reversed = true;
 3731        }
 3732
 3733        let mut pending_mode = self.selections.pending_mode().unwrap();
 3734        match &mut pending_mode {
 3735            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3736            _ => {}
 3737        }
 3738
 3739        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3740            SelectionEffects::scroll(Autoscroll::fit())
 3741        } else {
 3742            SelectionEffects::no_scroll()
 3743        };
 3744
 3745        self.change_selections(effects, window, cx, |s| {
 3746            s.set_pending(pending_selection.clone(), pending_mode);
 3747            s.set_is_extending(true);
 3748        });
 3749    }
 3750
 3751    fn begin_selection(
 3752        &mut self,
 3753        position: DisplayPoint,
 3754        add: bool,
 3755        click_count: usize,
 3756        window: &mut Window,
 3757        cx: &mut Context<Self>,
 3758    ) {
 3759        if !self.focus_handle.is_focused(window) {
 3760            self.last_focused_descendant = None;
 3761            window.focus(&self.focus_handle);
 3762        }
 3763
 3764        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3765        let buffer = display_map.buffer_snapshot();
 3766        let position = display_map.clip_point(position, Bias::Left);
 3767
 3768        let start;
 3769        let end;
 3770        let mode;
 3771        let mut auto_scroll;
 3772        match click_count {
 3773            1 => {
 3774                start = buffer.anchor_before(position.to_point(&display_map));
 3775                end = start;
 3776                mode = SelectMode::Character;
 3777                auto_scroll = true;
 3778            }
 3779            2 => {
 3780                let position = display_map
 3781                    .clip_point(position, Bias::Left)
 3782                    .to_offset(&display_map, Bias::Left);
 3783                let (range, _) = buffer.surrounding_word(position, None);
 3784                start = buffer.anchor_before(range.start);
 3785                end = buffer.anchor_before(range.end);
 3786                mode = SelectMode::Word(start..end);
 3787                auto_scroll = true;
 3788            }
 3789            3 => {
 3790                let position = display_map
 3791                    .clip_point(position, Bias::Left)
 3792                    .to_point(&display_map);
 3793                let line_start = display_map.prev_line_boundary(position).0;
 3794                let next_line_start = buffer.clip_point(
 3795                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3796                    Bias::Left,
 3797                );
 3798                start = buffer.anchor_before(line_start);
 3799                end = buffer.anchor_before(next_line_start);
 3800                mode = SelectMode::Line(start..end);
 3801                auto_scroll = true;
 3802            }
 3803            _ => {
 3804                start = buffer.anchor_before(MultiBufferOffset(0));
 3805                end = buffer.anchor_before(buffer.len());
 3806                mode = SelectMode::All;
 3807                auto_scroll = false;
 3808            }
 3809        }
 3810        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3811
 3812        let point_to_delete: Option<usize> = {
 3813            let selected_points: Vec<Selection<Point>> =
 3814                self.selections.disjoint_in_range(start..end, &display_map);
 3815
 3816            if !add || click_count > 1 {
 3817                None
 3818            } else if !selected_points.is_empty() {
 3819                Some(selected_points[0].id)
 3820            } else {
 3821                let clicked_point_already_selected =
 3822                    self.selections.disjoint_anchors().iter().find(|selection| {
 3823                        selection.start.to_point(buffer) == start.to_point(buffer)
 3824                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3825                    });
 3826
 3827                clicked_point_already_selected.map(|selection| selection.id)
 3828            }
 3829        };
 3830
 3831        let selections_count = self.selections.count();
 3832        let effects = if auto_scroll {
 3833            SelectionEffects::default()
 3834        } else {
 3835            SelectionEffects::no_scroll()
 3836        };
 3837
 3838        self.change_selections(effects, window, cx, |s| {
 3839            if let Some(point_to_delete) = point_to_delete {
 3840                s.delete(point_to_delete);
 3841
 3842                if selections_count == 1 {
 3843                    s.set_pending_anchor_range(start..end, mode);
 3844                }
 3845            } else {
 3846                if !add {
 3847                    s.clear_disjoint();
 3848                }
 3849
 3850                s.set_pending_anchor_range(start..end, mode);
 3851            }
 3852        });
 3853    }
 3854
 3855    fn begin_columnar_selection(
 3856        &mut self,
 3857        position: DisplayPoint,
 3858        goal_column: u32,
 3859        reset: bool,
 3860        mode: ColumnarMode,
 3861        window: &mut Window,
 3862        cx: &mut Context<Self>,
 3863    ) {
 3864        if !self.focus_handle.is_focused(window) {
 3865            self.last_focused_descendant = None;
 3866            window.focus(&self.focus_handle);
 3867        }
 3868
 3869        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3870
 3871        if reset {
 3872            let pointer_position = display_map
 3873                .buffer_snapshot()
 3874                .anchor_before(position.to_point(&display_map));
 3875
 3876            self.change_selections(
 3877                SelectionEffects::scroll(Autoscroll::newest()),
 3878                window,
 3879                cx,
 3880                |s| {
 3881                    s.clear_disjoint();
 3882                    s.set_pending_anchor_range(
 3883                        pointer_position..pointer_position,
 3884                        SelectMode::Character,
 3885                    );
 3886                },
 3887            );
 3888        };
 3889
 3890        let tail = self.selections.newest::<Point>(&display_map).tail();
 3891        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3892        self.columnar_selection_state = match mode {
 3893            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3894                selection_tail: selection_anchor,
 3895                display_point: if reset {
 3896                    if position.column() != goal_column {
 3897                        Some(DisplayPoint::new(position.row(), goal_column))
 3898                    } else {
 3899                        None
 3900                    }
 3901                } else {
 3902                    None
 3903                },
 3904            }),
 3905            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3906                selection_tail: selection_anchor,
 3907            }),
 3908        };
 3909
 3910        if !reset {
 3911            self.select_columns(position, goal_column, &display_map, window, cx);
 3912        }
 3913    }
 3914
 3915    fn update_selection(
 3916        &mut self,
 3917        position: DisplayPoint,
 3918        goal_column: u32,
 3919        scroll_delta: gpui::Point<f32>,
 3920        window: &mut Window,
 3921        cx: &mut Context<Self>,
 3922    ) {
 3923        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3924
 3925        if self.columnar_selection_state.is_some() {
 3926            self.select_columns(position, goal_column, &display_map, window, cx);
 3927        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3928            let buffer = display_map.buffer_snapshot();
 3929            let head;
 3930            let tail;
 3931            let mode = self.selections.pending_mode().unwrap();
 3932            match &mode {
 3933                SelectMode::Character => {
 3934                    head = position.to_point(&display_map);
 3935                    tail = pending.tail().to_point(buffer);
 3936                }
 3937                SelectMode::Word(original_range) => {
 3938                    let offset = display_map
 3939                        .clip_point(position, Bias::Left)
 3940                        .to_offset(&display_map, Bias::Left);
 3941                    let original_range = original_range.to_offset(buffer);
 3942
 3943                    let head_offset = if buffer.is_inside_word(offset, None)
 3944                        || original_range.contains(&offset)
 3945                    {
 3946                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3947                        if word_range.start < original_range.start {
 3948                            word_range.start
 3949                        } else {
 3950                            word_range.end
 3951                        }
 3952                    } else {
 3953                        offset
 3954                    };
 3955
 3956                    head = head_offset.to_point(buffer);
 3957                    if head_offset <= original_range.start {
 3958                        tail = original_range.end.to_point(buffer);
 3959                    } else {
 3960                        tail = original_range.start.to_point(buffer);
 3961                    }
 3962                }
 3963                SelectMode::Line(original_range) => {
 3964                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3965
 3966                    let position = display_map
 3967                        .clip_point(position, Bias::Left)
 3968                        .to_point(&display_map);
 3969                    let line_start = display_map.prev_line_boundary(position).0;
 3970                    let next_line_start = buffer.clip_point(
 3971                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3972                        Bias::Left,
 3973                    );
 3974
 3975                    if line_start < original_range.start {
 3976                        head = line_start
 3977                    } else {
 3978                        head = next_line_start
 3979                    }
 3980
 3981                    if head <= original_range.start {
 3982                        tail = original_range.end;
 3983                    } else {
 3984                        tail = original_range.start;
 3985                    }
 3986                }
 3987                SelectMode::All => {
 3988                    return;
 3989                }
 3990            };
 3991
 3992            if head < tail {
 3993                pending.start = buffer.anchor_before(head);
 3994                pending.end = buffer.anchor_before(tail);
 3995                pending.reversed = true;
 3996            } else {
 3997                pending.start = buffer.anchor_before(tail);
 3998                pending.end = buffer.anchor_before(head);
 3999                pending.reversed = false;
 4000            }
 4001
 4002            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4003                s.set_pending(pending.clone(), mode);
 4004            });
 4005        } else {
 4006            log::error!("update_selection dispatched with no pending selection");
 4007            return;
 4008        }
 4009
 4010        self.apply_scroll_delta(scroll_delta, window, cx);
 4011        cx.notify();
 4012    }
 4013
 4014    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4015        self.columnar_selection_state.take();
 4016        if let Some(pending_mode) = self.selections.pending_mode() {
 4017            let selections = self
 4018                .selections
 4019                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4020            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4021                s.select(selections);
 4022                s.clear_pending();
 4023                if s.is_extending() {
 4024                    s.set_is_extending(false);
 4025                } else {
 4026                    s.set_select_mode(pending_mode);
 4027                }
 4028            });
 4029        }
 4030    }
 4031
 4032    fn select_columns(
 4033        &mut self,
 4034        head: DisplayPoint,
 4035        goal_column: u32,
 4036        display_map: &DisplaySnapshot,
 4037        window: &mut Window,
 4038        cx: &mut Context<Self>,
 4039    ) {
 4040        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4041            return;
 4042        };
 4043
 4044        let tail = match columnar_state {
 4045            ColumnarSelectionState::FromMouse {
 4046                selection_tail,
 4047                display_point,
 4048            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4049            ColumnarSelectionState::FromSelection { selection_tail } => {
 4050                selection_tail.to_display_point(display_map)
 4051            }
 4052        };
 4053
 4054        let start_row = cmp::min(tail.row(), head.row());
 4055        let end_row = cmp::max(tail.row(), head.row());
 4056        let start_column = cmp::min(tail.column(), goal_column);
 4057        let end_column = cmp::max(tail.column(), goal_column);
 4058        let reversed = start_column < tail.column();
 4059
 4060        let selection_ranges = (start_row.0..=end_row.0)
 4061            .map(DisplayRow)
 4062            .filter_map(|row| {
 4063                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4064                    || start_column <= display_map.line_len(row))
 4065                    && !display_map.is_block_line(row)
 4066                {
 4067                    let start = display_map
 4068                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4069                        .to_point(display_map);
 4070                    let end = display_map
 4071                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4072                        .to_point(display_map);
 4073                    if reversed {
 4074                        Some(end..start)
 4075                    } else {
 4076                        Some(start..end)
 4077                    }
 4078                } else {
 4079                    None
 4080                }
 4081            })
 4082            .collect::<Vec<_>>();
 4083        if selection_ranges.is_empty() {
 4084            return;
 4085        }
 4086
 4087        let ranges = match columnar_state {
 4088            ColumnarSelectionState::FromMouse { .. } => {
 4089                let mut non_empty_ranges = selection_ranges
 4090                    .iter()
 4091                    .filter(|selection_range| selection_range.start != selection_range.end)
 4092                    .peekable();
 4093                if non_empty_ranges.peek().is_some() {
 4094                    non_empty_ranges.cloned().collect()
 4095                } else {
 4096                    selection_ranges
 4097                }
 4098            }
 4099            _ => selection_ranges,
 4100        };
 4101
 4102        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4103            s.select_ranges(ranges);
 4104        });
 4105        cx.notify();
 4106    }
 4107
 4108    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4109        self.selections
 4110            .all_adjusted(snapshot)
 4111            .iter()
 4112            .any(|selection| !selection.is_empty())
 4113    }
 4114
 4115    pub fn has_pending_nonempty_selection(&self) -> bool {
 4116        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4117            Some(Selection { start, end, .. }) => start != end,
 4118            None => false,
 4119        };
 4120
 4121        pending_nonempty_selection
 4122            || (self.columnar_selection_state.is_some()
 4123                && self.selections.disjoint_anchors().len() > 1)
 4124    }
 4125
 4126    pub fn has_pending_selection(&self) -> bool {
 4127        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4128    }
 4129
 4130    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4131        self.selection_mark_mode = false;
 4132        self.selection_drag_state = SelectionDragState::None;
 4133
 4134        if self.dismiss_menus_and_popups(true, window, cx) {
 4135            cx.notify();
 4136            return;
 4137        }
 4138        if self.clear_expanded_diff_hunks(cx) {
 4139            cx.notify();
 4140            return;
 4141        }
 4142        if self.show_git_blame_gutter {
 4143            self.show_git_blame_gutter = false;
 4144            cx.notify();
 4145            return;
 4146        }
 4147
 4148        if self.mode.is_full()
 4149            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4150        {
 4151            cx.notify();
 4152            return;
 4153        }
 4154
 4155        cx.propagate();
 4156    }
 4157
 4158    pub fn dismiss_menus_and_popups(
 4159        &mut self,
 4160        is_user_requested: bool,
 4161        window: &mut Window,
 4162        cx: &mut Context<Self>,
 4163    ) -> bool {
 4164        let mut dismissed = false;
 4165
 4166        dismissed |= self.take_rename(false, window, cx).is_some();
 4167        dismissed |= self.hide_blame_popover(true, cx);
 4168        dismissed |= hide_hover(self, cx);
 4169        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4170        dismissed |= self.hide_context_menu(window, cx).is_some();
 4171        dismissed |= self.mouse_context_menu.take().is_some();
 4172        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4173        dismissed |= self.snippet_stack.pop().is_some();
 4174
 4175        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4176            self.dismiss_diagnostics(cx);
 4177            dismissed = true;
 4178        }
 4179
 4180        dismissed
 4181    }
 4182
 4183    fn linked_editing_ranges_for(
 4184        &self,
 4185        selection: Range<text::Anchor>,
 4186        cx: &App,
 4187    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4188        if self.linked_edit_ranges.is_empty() {
 4189            return None;
 4190        }
 4191        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4192            selection.end.buffer_id.and_then(|end_buffer_id| {
 4193                if selection.start.buffer_id != Some(end_buffer_id) {
 4194                    return None;
 4195                }
 4196                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4197                let snapshot = buffer.read(cx).snapshot();
 4198                self.linked_edit_ranges
 4199                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4200                    .map(|ranges| (ranges, snapshot, buffer))
 4201            })?;
 4202        use text::ToOffset as TO;
 4203        // find offset from the start of current range to current cursor position
 4204        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4205
 4206        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4207        let start_difference = start_offset - start_byte_offset;
 4208        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4209        let end_difference = end_offset - start_byte_offset;
 4210        // Current range has associated linked ranges.
 4211        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4212        for range in linked_ranges.iter() {
 4213            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4214            let end_offset = start_offset + end_difference;
 4215            let start_offset = start_offset + start_difference;
 4216            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4217                continue;
 4218            }
 4219            if self.selections.disjoint_anchor_ranges().any(|s| {
 4220                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4221                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4222                {
 4223                    return false;
 4224                }
 4225                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4226                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4227            }) {
 4228                continue;
 4229            }
 4230            let start = buffer_snapshot.anchor_after(start_offset);
 4231            let end = buffer_snapshot.anchor_after(end_offset);
 4232            linked_edits
 4233                .entry(buffer.clone())
 4234                .or_default()
 4235                .push(start..end);
 4236        }
 4237        Some(linked_edits)
 4238    }
 4239
 4240    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4241        let text: Arc<str> = text.into();
 4242
 4243        if self.read_only(cx) {
 4244            return;
 4245        }
 4246
 4247        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4248
 4249        self.unfold_buffers_with_selections(cx);
 4250
 4251        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4252        let mut bracket_inserted = false;
 4253        let mut edits = Vec::new();
 4254        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4255        let mut new_selections = Vec::with_capacity(selections.len());
 4256        let mut new_autoclose_regions = Vec::new();
 4257        let snapshot = self.buffer.read(cx).read(cx);
 4258        let mut clear_linked_edit_ranges = false;
 4259
 4260        for (selection, autoclose_region) in
 4261            self.selections_with_autoclose_regions(selections, &snapshot)
 4262        {
 4263            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4264                // Determine if the inserted text matches the opening or closing
 4265                // bracket of any of this language's bracket pairs.
 4266                let mut bracket_pair = None;
 4267                let mut is_bracket_pair_start = false;
 4268                let mut is_bracket_pair_end = false;
 4269                if !text.is_empty() {
 4270                    let mut bracket_pair_matching_end = None;
 4271                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4272                    //  and they are removing the character that triggered IME popup.
 4273                    for (pair, enabled) in scope.brackets() {
 4274                        if !pair.close && !pair.surround {
 4275                            continue;
 4276                        }
 4277
 4278                        if enabled && pair.start.ends_with(text.as_ref()) {
 4279                            let prefix_len = pair.start.len() - text.len();
 4280                            let preceding_text_matches_prefix = prefix_len == 0
 4281                                || (selection.start.column >= (prefix_len as u32)
 4282                                    && snapshot.contains_str_at(
 4283                                        Point::new(
 4284                                            selection.start.row,
 4285                                            selection.start.column - (prefix_len as u32),
 4286                                        ),
 4287                                        &pair.start[..prefix_len],
 4288                                    ));
 4289                            if preceding_text_matches_prefix {
 4290                                bracket_pair = Some(pair.clone());
 4291                                is_bracket_pair_start = true;
 4292                                break;
 4293                            }
 4294                        }
 4295                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4296                        {
 4297                            // take first bracket pair matching end, but don't break in case a later bracket
 4298                            // pair matches start
 4299                            bracket_pair_matching_end = Some(pair.clone());
 4300                        }
 4301                    }
 4302                    if let Some(end) = bracket_pair_matching_end
 4303                        && bracket_pair.is_none()
 4304                    {
 4305                        bracket_pair = Some(end);
 4306                        is_bracket_pair_end = true;
 4307                    }
 4308                }
 4309
 4310                if let Some(bracket_pair) = bracket_pair {
 4311                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4312                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4313                    let auto_surround =
 4314                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4315                    if selection.is_empty() {
 4316                        if is_bracket_pair_start {
 4317                            // If the inserted text is a suffix of an opening bracket and the
 4318                            // selection is preceded by the rest of the opening bracket, then
 4319                            // insert the closing bracket.
 4320                            let following_text_allows_autoclose = snapshot
 4321                                .chars_at(selection.start)
 4322                                .next()
 4323                                .is_none_or(|c| scope.should_autoclose_before(c));
 4324
 4325                            let preceding_text_allows_autoclose = selection.start.column == 0
 4326                                || snapshot
 4327                                    .reversed_chars_at(selection.start)
 4328                                    .next()
 4329                                    .is_none_or(|c| {
 4330                                        bracket_pair.start != bracket_pair.end
 4331                                            || !snapshot
 4332                                                .char_classifier_at(selection.start)
 4333                                                .is_word(c)
 4334                                    });
 4335
 4336                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4337                                && bracket_pair.start.len() == 1
 4338                            {
 4339                                let target = bracket_pair.start.chars().next().unwrap();
 4340                                let current_line_count = snapshot
 4341                                    .reversed_chars_at(selection.start)
 4342                                    .take_while(|&c| c != '\n')
 4343                                    .filter(|&c| c == target)
 4344                                    .count();
 4345                                current_line_count % 2 == 1
 4346                            } else {
 4347                                false
 4348                            };
 4349
 4350                            if autoclose
 4351                                && bracket_pair.close
 4352                                && following_text_allows_autoclose
 4353                                && preceding_text_allows_autoclose
 4354                                && !is_closing_quote
 4355                            {
 4356                                let anchor = snapshot.anchor_before(selection.end);
 4357                                new_selections.push((selection.map(|_| anchor), text.len()));
 4358                                new_autoclose_regions.push((
 4359                                    anchor,
 4360                                    text.len(),
 4361                                    selection.id,
 4362                                    bracket_pair.clone(),
 4363                                ));
 4364                                edits.push((
 4365                                    selection.range(),
 4366                                    format!("{}{}", text, bracket_pair.end).into(),
 4367                                ));
 4368                                bracket_inserted = true;
 4369                                continue;
 4370                            }
 4371                        }
 4372
 4373                        if let Some(region) = autoclose_region {
 4374                            // If the selection is followed by an auto-inserted closing bracket,
 4375                            // then don't insert that closing bracket again; just move the selection
 4376                            // past the closing bracket.
 4377                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4378                                && text.as_ref() == region.pair.end.as_str()
 4379                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4380                            if should_skip {
 4381                                let anchor = snapshot.anchor_after(selection.end);
 4382                                new_selections
 4383                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4384                                continue;
 4385                            }
 4386                        }
 4387
 4388                        let always_treat_brackets_as_autoclosed = snapshot
 4389                            .language_settings_at(selection.start, cx)
 4390                            .always_treat_brackets_as_autoclosed;
 4391                        if always_treat_brackets_as_autoclosed
 4392                            && is_bracket_pair_end
 4393                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4394                        {
 4395                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4396                            // and the inserted text is a closing bracket and the selection is followed
 4397                            // by the closing bracket then move the selection past the closing bracket.
 4398                            let anchor = snapshot.anchor_after(selection.end);
 4399                            new_selections.push((selection.map(|_| anchor), text.len()));
 4400                            continue;
 4401                        }
 4402                    }
 4403                    // If an opening bracket is 1 character long and is typed while
 4404                    // text is selected, then surround that text with the bracket pair.
 4405                    else if auto_surround
 4406                        && bracket_pair.surround
 4407                        && is_bracket_pair_start
 4408                        && bracket_pair.start.chars().count() == 1
 4409                    {
 4410                        edits.push((selection.start..selection.start, text.clone()));
 4411                        edits.push((
 4412                            selection.end..selection.end,
 4413                            bracket_pair.end.as_str().into(),
 4414                        ));
 4415                        bracket_inserted = true;
 4416                        new_selections.push((
 4417                            Selection {
 4418                                id: selection.id,
 4419                                start: snapshot.anchor_after(selection.start),
 4420                                end: snapshot.anchor_before(selection.end),
 4421                                reversed: selection.reversed,
 4422                                goal: selection.goal,
 4423                            },
 4424                            0,
 4425                        ));
 4426                        continue;
 4427                    }
 4428                }
 4429            }
 4430
 4431            if self.auto_replace_emoji_shortcode
 4432                && selection.is_empty()
 4433                && text.as_ref().ends_with(':')
 4434                && let Some(possible_emoji_short_code) =
 4435                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4436                && !possible_emoji_short_code.is_empty()
 4437                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4438            {
 4439                let emoji_shortcode_start = Point::new(
 4440                    selection.start.row,
 4441                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4442                );
 4443
 4444                // Remove shortcode from buffer
 4445                edits.push((
 4446                    emoji_shortcode_start..selection.start,
 4447                    "".to_string().into(),
 4448                ));
 4449                new_selections.push((
 4450                    Selection {
 4451                        id: selection.id,
 4452                        start: snapshot.anchor_after(emoji_shortcode_start),
 4453                        end: snapshot.anchor_before(selection.start),
 4454                        reversed: selection.reversed,
 4455                        goal: selection.goal,
 4456                    },
 4457                    0,
 4458                ));
 4459
 4460                // Insert emoji
 4461                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4462                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4463                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4464
 4465                continue;
 4466            }
 4467
 4468            // If not handling any auto-close operation, then just replace the selected
 4469            // text with the given input and move the selection to the end of the
 4470            // newly inserted text.
 4471            let anchor = snapshot.anchor_after(selection.end);
 4472            if !self.linked_edit_ranges.is_empty() {
 4473                let start_anchor = snapshot.anchor_before(selection.start);
 4474
 4475                let is_word_char = text.chars().next().is_none_or(|char| {
 4476                    let classifier = snapshot
 4477                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4478                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4479                    classifier.is_word(char)
 4480                });
 4481
 4482                if is_word_char {
 4483                    if let Some(ranges) = self
 4484                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4485                    {
 4486                        for (buffer, edits) in ranges {
 4487                            linked_edits
 4488                                .entry(buffer.clone())
 4489                                .or_default()
 4490                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4491                        }
 4492                    }
 4493                } else {
 4494                    clear_linked_edit_ranges = true;
 4495                }
 4496            }
 4497
 4498            new_selections.push((selection.map(|_| anchor), 0));
 4499            edits.push((selection.start..selection.end, text.clone()));
 4500        }
 4501
 4502        drop(snapshot);
 4503
 4504        self.transact(window, cx, |this, window, cx| {
 4505            if clear_linked_edit_ranges {
 4506                this.linked_edit_ranges.clear();
 4507            }
 4508            let initial_buffer_versions =
 4509                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4510
 4511            this.buffer.update(cx, |buffer, cx| {
 4512                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4513            });
 4514            for (buffer, edits) in linked_edits {
 4515                buffer.update(cx, |buffer, cx| {
 4516                    let snapshot = buffer.snapshot();
 4517                    let edits = edits
 4518                        .into_iter()
 4519                        .map(|(range, text)| {
 4520                            use text::ToPoint as TP;
 4521                            let end_point = TP::to_point(&range.end, &snapshot);
 4522                            let start_point = TP::to_point(&range.start, &snapshot);
 4523                            (start_point..end_point, text)
 4524                        })
 4525                        .sorted_by_key(|(range, _)| range.start);
 4526                    buffer.edit(edits, None, cx);
 4527                })
 4528            }
 4529            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4530            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4531            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4532            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4533                new_anchor_selections,
 4534                &map,
 4535            )
 4536            .zip(new_selection_deltas)
 4537            .map(|(selection, delta)| Selection {
 4538                id: selection.id,
 4539                start: selection.start + delta,
 4540                end: selection.end + delta,
 4541                reversed: selection.reversed,
 4542                goal: SelectionGoal::None,
 4543            })
 4544            .collect::<Vec<_>>();
 4545
 4546            let mut i = 0;
 4547            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4548                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4549                let start = map.buffer_snapshot().anchor_before(position);
 4550                let end = map.buffer_snapshot().anchor_after(position);
 4551                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4552                    match existing_state
 4553                        .range
 4554                        .start
 4555                        .cmp(&start, map.buffer_snapshot())
 4556                    {
 4557                        Ordering::Less => i += 1,
 4558                        Ordering::Greater => break,
 4559                        Ordering::Equal => {
 4560                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4561                                Ordering::Less => i += 1,
 4562                                Ordering::Equal => break,
 4563                                Ordering::Greater => break,
 4564                            }
 4565                        }
 4566                    }
 4567                }
 4568                this.autoclose_regions.insert(
 4569                    i,
 4570                    AutocloseRegion {
 4571                        selection_id,
 4572                        range: start..end,
 4573                        pair,
 4574                    },
 4575                );
 4576            }
 4577
 4578            let had_active_edit_prediction = this.has_active_edit_prediction();
 4579            this.change_selections(
 4580                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4581                window,
 4582                cx,
 4583                |s| s.select(new_selections),
 4584            );
 4585
 4586            if !bracket_inserted
 4587                && let Some(on_type_format_task) =
 4588                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4589            {
 4590                on_type_format_task.detach_and_log_err(cx);
 4591            }
 4592
 4593            let editor_settings = EditorSettings::get_global(cx);
 4594            if bracket_inserted
 4595                && (editor_settings.auto_signature_help
 4596                    || editor_settings.show_signature_help_after_edits)
 4597            {
 4598                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4599            }
 4600
 4601            let trigger_in_words =
 4602                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4603            if this.hard_wrap.is_some() {
 4604                let latest: Range<Point> = this.selections.newest(&map).range();
 4605                if latest.is_empty()
 4606                    && this
 4607                        .buffer()
 4608                        .read(cx)
 4609                        .snapshot(cx)
 4610                        .line_len(MultiBufferRow(latest.start.row))
 4611                        == latest.start.column
 4612                {
 4613                    this.rewrap_impl(
 4614                        RewrapOptions {
 4615                            override_language_settings: true,
 4616                            preserve_existing_whitespace: true,
 4617                        },
 4618                        cx,
 4619                    )
 4620                }
 4621            }
 4622            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4623            refresh_linked_ranges(this, window, cx);
 4624            this.refresh_edit_prediction(true, false, window, cx);
 4625            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4626        });
 4627    }
 4628
 4629    fn find_possible_emoji_shortcode_at_position(
 4630        snapshot: &MultiBufferSnapshot,
 4631        position: Point,
 4632    ) -> Option<String> {
 4633        let mut chars = Vec::new();
 4634        let mut found_colon = false;
 4635        for char in snapshot.reversed_chars_at(position).take(100) {
 4636            // Found a possible emoji shortcode in the middle of the buffer
 4637            if found_colon {
 4638                if char.is_whitespace() {
 4639                    chars.reverse();
 4640                    return Some(chars.iter().collect());
 4641                }
 4642                // If the previous character is not a whitespace, we are in the middle of a word
 4643                // and we only want to complete the shortcode if the word is made up of other emojis
 4644                let mut containing_word = String::new();
 4645                for ch in snapshot
 4646                    .reversed_chars_at(position)
 4647                    .skip(chars.len() + 1)
 4648                    .take(100)
 4649                {
 4650                    if ch.is_whitespace() {
 4651                        break;
 4652                    }
 4653                    containing_word.push(ch);
 4654                }
 4655                let containing_word = containing_word.chars().rev().collect::<String>();
 4656                if util::word_consists_of_emojis(containing_word.as_str()) {
 4657                    chars.reverse();
 4658                    return Some(chars.iter().collect());
 4659                }
 4660            }
 4661
 4662            if char.is_whitespace() || !char.is_ascii() {
 4663                return None;
 4664            }
 4665            if char == ':' {
 4666                found_colon = true;
 4667            } else {
 4668                chars.push(char);
 4669            }
 4670        }
 4671        // Found a possible emoji shortcode at the beginning of the buffer
 4672        chars.reverse();
 4673        Some(chars.iter().collect())
 4674    }
 4675
 4676    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4677        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4678        self.transact(window, cx, |this, window, cx| {
 4679            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4680                let selections = this
 4681                    .selections
 4682                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4683                let multi_buffer = this.buffer.read(cx);
 4684                let buffer = multi_buffer.snapshot(cx);
 4685                selections
 4686                    .iter()
 4687                    .map(|selection| {
 4688                        let start_point = selection.start.to_point(&buffer);
 4689                        let mut existing_indent =
 4690                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4691                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4692                        let start = selection.start;
 4693                        let end = selection.end;
 4694                        let selection_is_empty = start == end;
 4695                        let language_scope = buffer.language_scope_at(start);
 4696                        let (
 4697                            comment_delimiter,
 4698                            doc_delimiter,
 4699                            insert_extra_newline,
 4700                            indent_on_newline,
 4701                            indent_on_extra_newline,
 4702                        ) = if let Some(language) = &language_scope {
 4703                            let mut insert_extra_newline =
 4704                                insert_extra_newline_brackets(&buffer, start..end, language)
 4705                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4706
 4707                            // Comment extension on newline is allowed only for cursor selections
 4708                            let comment_delimiter = maybe!({
 4709                                if !selection_is_empty {
 4710                                    return None;
 4711                                }
 4712
 4713                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4714                                    return None;
 4715                                }
 4716
 4717                                let delimiters = language.line_comment_prefixes();
 4718                                let max_len_of_delimiter =
 4719                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4720                                let (snapshot, range) =
 4721                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4722
 4723                                let num_of_whitespaces = snapshot
 4724                                    .chars_for_range(range.clone())
 4725                                    .take_while(|c| c.is_whitespace())
 4726                                    .count();
 4727                                let comment_candidate = snapshot
 4728                                    .chars_for_range(range.clone())
 4729                                    .skip(num_of_whitespaces)
 4730                                    .take(max_len_of_delimiter)
 4731                                    .collect::<String>();
 4732                                let (delimiter, trimmed_len) = delimiters
 4733                                    .iter()
 4734                                    .filter_map(|delimiter| {
 4735                                        let prefix = delimiter.trim_end();
 4736                                        if comment_candidate.starts_with(prefix) {
 4737                                            Some((delimiter, prefix.len()))
 4738                                        } else {
 4739                                            None
 4740                                        }
 4741                                    })
 4742                                    .max_by_key(|(_, len)| *len)?;
 4743
 4744                                if let Some(BlockCommentConfig {
 4745                                    start: block_start, ..
 4746                                }) = language.block_comment()
 4747                                {
 4748                                    let block_start_trimmed = block_start.trim_end();
 4749                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4750                                        let line_content = snapshot
 4751                                            .chars_for_range(range)
 4752                                            .skip(num_of_whitespaces)
 4753                                            .take(block_start_trimmed.len())
 4754                                            .collect::<String>();
 4755
 4756                                        if line_content.starts_with(block_start_trimmed) {
 4757                                            return None;
 4758                                        }
 4759                                    }
 4760                                }
 4761
 4762                                let cursor_is_placed_after_comment_marker =
 4763                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4764                                if cursor_is_placed_after_comment_marker {
 4765                                    Some(delimiter.clone())
 4766                                } else {
 4767                                    None
 4768                                }
 4769                            });
 4770
 4771                            let mut indent_on_newline = IndentSize::spaces(0);
 4772                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4773
 4774                            let doc_delimiter = maybe!({
 4775                                if !selection_is_empty {
 4776                                    return None;
 4777                                }
 4778
 4779                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4780                                    return None;
 4781                                }
 4782
 4783                                let BlockCommentConfig {
 4784                                    start: start_tag,
 4785                                    end: end_tag,
 4786                                    prefix: delimiter,
 4787                                    tab_size: len,
 4788                                } = language.documentation_comment()?;
 4789                                let is_within_block_comment = buffer
 4790                                    .language_scope_at(start_point)
 4791                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4792                                if !is_within_block_comment {
 4793                                    return None;
 4794                                }
 4795
 4796                                let (snapshot, range) =
 4797                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4798
 4799                                let num_of_whitespaces = snapshot
 4800                                    .chars_for_range(range.clone())
 4801                                    .take_while(|c| c.is_whitespace())
 4802                                    .count();
 4803
 4804                                // 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.
 4805                                let column = start_point.column;
 4806                                let cursor_is_after_start_tag = {
 4807                                    let start_tag_len = start_tag.len();
 4808                                    let start_tag_line = snapshot
 4809                                        .chars_for_range(range.clone())
 4810                                        .skip(num_of_whitespaces)
 4811                                        .take(start_tag_len)
 4812                                        .collect::<String>();
 4813                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4814                                        num_of_whitespaces + start_tag_len <= column as usize
 4815                                    } else {
 4816                                        false
 4817                                    }
 4818                                };
 4819
 4820                                let cursor_is_after_delimiter = {
 4821                                    let delimiter_trim = delimiter.trim_end();
 4822                                    let delimiter_line = snapshot
 4823                                        .chars_for_range(range.clone())
 4824                                        .skip(num_of_whitespaces)
 4825                                        .take(delimiter_trim.len())
 4826                                        .collect::<String>();
 4827                                    if delimiter_line.starts_with(delimiter_trim) {
 4828                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4829                                    } else {
 4830                                        false
 4831                                    }
 4832                                };
 4833
 4834                                let cursor_is_before_end_tag_if_exists = {
 4835                                    let mut char_position = 0u32;
 4836                                    let mut end_tag_offset = None;
 4837
 4838                                    'outer: for chunk in snapshot.text_for_range(range) {
 4839                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4840                                            let chars_before_match =
 4841                                                chunk[..byte_pos].chars().count() as u32;
 4842                                            end_tag_offset =
 4843                                                Some(char_position + chars_before_match);
 4844                                            break 'outer;
 4845                                        }
 4846                                        char_position += chunk.chars().count() as u32;
 4847                                    }
 4848
 4849                                    if let Some(end_tag_offset) = end_tag_offset {
 4850                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4851                                        if cursor_is_after_start_tag {
 4852                                            if cursor_is_before_end_tag {
 4853                                                insert_extra_newline = true;
 4854                                            }
 4855                                            let cursor_is_at_start_of_end_tag =
 4856                                                column == end_tag_offset;
 4857                                            if cursor_is_at_start_of_end_tag {
 4858                                                indent_on_extra_newline.len = *len;
 4859                                            }
 4860                                        }
 4861                                        cursor_is_before_end_tag
 4862                                    } else {
 4863                                        true
 4864                                    }
 4865                                };
 4866
 4867                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4868                                    && cursor_is_before_end_tag_if_exists
 4869                                {
 4870                                    if cursor_is_after_start_tag {
 4871                                        indent_on_newline.len = *len;
 4872                                    }
 4873                                    Some(delimiter.clone())
 4874                                } else {
 4875                                    None
 4876                                }
 4877                            });
 4878
 4879                            (
 4880                                comment_delimiter,
 4881                                doc_delimiter,
 4882                                insert_extra_newline,
 4883                                indent_on_newline,
 4884                                indent_on_extra_newline,
 4885                            )
 4886                        } else {
 4887                            (
 4888                                None,
 4889                                None,
 4890                                false,
 4891                                IndentSize::default(),
 4892                                IndentSize::default(),
 4893                            )
 4894                        };
 4895
 4896                        let prevent_auto_indent = doc_delimiter.is_some();
 4897                        let delimiter = comment_delimiter.or(doc_delimiter);
 4898
 4899                        let capacity_for_delimiter =
 4900                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4901                        let mut new_text = String::with_capacity(
 4902                            1 + capacity_for_delimiter
 4903                                + existing_indent.len as usize
 4904                                + indent_on_newline.len as usize
 4905                                + indent_on_extra_newline.len as usize,
 4906                        );
 4907                        new_text.push('\n');
 4908                        new_text.extend(existing_indent.chars());
 4909                        new_text.extend(indent_on_newline.chars());
 4910
 4911                        if let Some(delimiter) = &delimiter {
 4912                            new_text.push_str(delimiter);
 4913                        }
 4914
 4915                        if insert_extra_newline {
 4916                            new_text.push('\n');
 4917                            new_text.extend(existing_indent.chars());
 4918                            new_text.extend(indent_on_extra_newline.chars());
 4919                        }
 4920
 4921                        let anchor = buffer.anchor_after(end);
 4922                        let new_selection = selection.map(|_| anchor);
 4923                        (
 4924                            ((start..end, new_text), prevent_auto_indent),
 4925                            (insert_extra_newline, new_selection),
 4926                        )
 4927                    })
 4928                    .unzip()
 4929            };
 4930
 4931            let mut auto_indent_edits = Vec::new();
 4932            let mut edits = Vec::new();
 4933            for (edit, prevent_auto_indent) in edits_with_flags {
 4934                if prevent_auto_indent {
 4935                    edits.push(edit);
 4936                } else {
 4937                    auto_indent_edits.push(edit);
 4938                }
 4939            }
 4940            if !edits.is_empty() {
 4941                this.edit(edits, cx);
 4942            }
 4943            if !auto_indent_edits.is_empty() {
 4944                this.edit_with_autoindent(auto_indent_edits, cx);
 4945            }
 4946
 4947            let buffer = this.buffer.read(cx).snapshot(cx);
 4948            let new_selections = selection_info
 4949                .into_iter()
 4950                .map(|(extra_newline_inserted, new_selection)| {
 4951                    let mut cursor = new_selection.end.to_point(&buffer);
 4952                    if extra_newline_inserted {
 4953                        cursor.row -= 1;
 4954                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4955                    }
 4956                    new_selection.map(|_| cursor)
 4957                })
 4958                .collect();
 4959
 4960            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4961            this.refresh_edit_prediction(true, false, window, cx);
 4962        });
 4963    }
 4964
 4965    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4966        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4967
 4968        let buffer = self.buffer.read(cx);
 4969        let snapshot = buffer.snapshot(cx);
 4970
 4971        let mut edits = Vec::new();
 4972        let mut rows = Vec::new();
 4973
 4974        for (rows_inserted, selection) in self
 4975            .selections
 4976            .all_adjusted(&self.display_snapshot(cx))
 4977            .into_iter()
 4978            .enumerate()
 4979        {
 4980            let cursor = selection.head();
 4981            let row = cursor.row;
 4982
 4983            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4984
 4985            let newline = "\n".to_string();
 4986            edits.push((start_of_line..start_of_line, newline));
 4987
 4988            rows.push(row + rows_inserted as u32);
 4989        }
 4990
 4991        self.transact(window, cx, |editor, window, cx| {
 4992            editor.edit(edits, cx);
 4993
 4994            editor.change_selections(Default::default(), window, cx, |s| {
 4995                let mut index = 0;
 4996                s.move_cursors_with(|map, _, _| {
 4997                    let row = rows[index];
 4998                    index += 1;
 4999
 5000                    let point = Point::new(row, 0);
 5001                    let boundary = map.next_line_boundary(point).1;
 5002                    let clipped = map.clip_point(boundary, Bias::Left);
 5003
 5004                    (clipped, SelectionGoal::None)
 5005                });
 5006            });
 5007
 5008            let mut indent_edits = Vec::new();
 5009            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5010            for row in rows {
 5011                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5012                for (row, indent) in indents {
 5013                    if indent.len == 0 {
 5014                        continue;
 5015                    }
 5016
 5017                    let text = match indent.kind {
 5018                        IndentKind::Space => " ".repeat(indent.len as usize),
 5019                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5020                    };
 5021                    let point = Point::new(row.0, 0);
 5022                    indent_edits.push((point..point, text));
 5023                }
 5024            }
 5025            editor.edit(indent_edits, cx);
 5026        });
 5027    }
 5028
 5029    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5030        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5031
 5032        let buffer = self.buffer.read(cx);
 5033        let snapshot = buffer.snapshot(cx);
 5034
 5035        let mut edits = Vec::new();
 5036        let mut rows = Vec::new();
 5037        let mut rows_inserted = 0;
 5038
 5039        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5040            let cursor = selection.head();
 5041            let row = cursor.row;
 5042
 5043            let point = Point::new(row + 1, 0);
 5044            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5045
 5046            let newline = "\n".to_string();
 5047            edits.push((start_of_line..start_of_line, newline));
 5048
 5049            rows_inserted += 1;
 5050            rows.push(row + rows_inserted);
 5051        }
 5052
 5053        self.transact(window, cx, |editor, window, cx| {
 5054            editor.edit(edits, cx);
 5055
 5056            editor.change_selections(Default::default(), window, cx, |s| {
 5057                let mut index = 0;
 5058                s.move_cursors_with(|map, _, _| {
 5059                    let row = rows[index];
 5060                    index += 1;
 5061
 5062                    let point = Point::new(row, 0);
 5063                    let boundary = map.next_line_boundary(point).1;
 5064                    let clipped = map.clip_point(boundary, Bias::Left);
 5065
 5066                    (clipped, SelectionGoal::None)
 5067                });
 5068            });
 5069
 5070            let mut indent_edits = Vec::new();
 5071            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5072            for row in rows {
 5073                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5074                for (row, indent) in indents {
 5075                    if indent.len == 0 {
 5076                        continue;
 5077                    }
 5078
 5079                    let text = match indent.kind {
 5080                        IndentKind::Space => " ".repeat(indent.len as usize),
 5081                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5082                    };
 5083                    let point = Point::new(row.0, 0);
 5084                    indent_edits.push((point..point, text));
 5085                }
 5086            }
 5087            editor.edit(indent_edits, cx);
 5088        });
 5089    }
 5090
 5091    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5092        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5093            original_indent_columns: Vec::new(),
 5094        });
 5095        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5096    }
 5097
 5098    fn insert_with_autoindent_mode(
 5099        &mut self,
 5100        text: &str,
 5101        autoindent_mode: Option<AutoindentMode>,
 5102        window: &mut Window,
 5103        cx: &mut Context<Self>,
 5104    ) {
 5105        if self.read_only(cx) {
 5106            return;
 5107        }
 5108
 5109        let text: Arc<str> = text.into();
 5110        self.transact(window, cx, |this, window, cx| {
 5111            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5112            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5113                let anchors = {
 5114                    let snapshot = buffer.read(cx);
 5115                    old_selections
 5116                        .iter()
 5117                        .map(|s| {
 5118                            let anchor = snapshot.anchor_after(s.head());
 5119                            s.map(|_| anchor)
 5120                        })
 5121                        .collect::<Vec<_>>()
 5122                };
 5123                buffer.edit(
 5124                    old_selections
 5125                        .iter()
 5126                        .map(|s| (s.start..s.end, text.clone())),
 5127                    autoindent_mode,
 5128                    cx,
 5129                );
 5130                anchors
 5131            });
 5132
 5133            this.change_selections(Default::default(), window, cx, |s| {
 5134                s.select_anchors(selection_anchors);
 5135            });
 5136
 5137            cx.notify();
 5138        });
 5139    }
 5140
 5141    fn trigger_completion_on_input(
 5142        &mut self,
 5143        text: &str,
 5144        trigger_in_words: bool,
 5145        window: &mut Window,
 5146        cx: &mut Context<Self>,
 5147    ) {
 5148        let completions_source = self
 5149            .context_menu
 5150            .borrow()
 5151            .as_ref()
 5152            .and_then(|menu| match menu {
 5153                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5154                CodeContextMenu::CodeActions(_) => None,
 5155            });
 5156
 5157        match completions_source {
 5158            Some(CompletionsMenuSource::Words { .. }) => {
 5159                self.open_or_update_completions_menu(
 5160                    Some(CompletionsMenuSource::Words {
 5161                        ignore_threshold: false,
 5162                    }),
 5163                    None,
 5164                    trigger_in_words,
 5165                    window,
 5166                    cx,
 5167                );
 5168            }
 5169            _ => self.open_or_update_completions_menu(
 5170                None,
 5171                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5172                true,
 5173                window,
 5174                cx,
 5175            ),
 5176        }
 5177    }
 5178
 5179    /// If any empty selections is touching the start of its innermost containing autoclose
 5180    /// region, expand it to select the brackets.
 5181    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5182        let selections = self
 5183            .selections
 5184            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5185        let buffer = self.buffer.read(cx).read(cx);
 5186        let new_selections = self
 5187            .selections_with_autoclose_regions(selections, &buffer)
 5188            .map(|(mut selection, region)| {
 5189                if !selection.is_empty() {
 5190                    return selection;
 5191                }
 5192
 5193                if let Some(region) = region {
 5194                    let mut range = region.range.to_offset(&buffer);
 5195                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5196                        range.start -= region.pair.start.len();
 5197                        if buffer.contains_str_at(range.start, &region.pair.start)
 5198                            && buffer.contains_str_at(range.end, &region.pair.end)
 5199                        {
 5200                            range.end += region.pair.end.len();
 5201                            selection.start = range.start;
 5202                            selection.end = range.end;
 5203
 5204                            return selection;
 5205                        }
 5206                    }
 5207                }
 5208
 5209                let always_treat_brackets_as_autoclosed = buffer
 5210                    .language_settings_at(selection.start, cx)
 5211                    .always_treat_brackets_as_autoclosed;
 5212
 5213                if !always_treat_brackets_as_autoclosed {
 5214                    return selection;
 5215                }
 5216
 5217                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5218                    for (pair, enabled) in scope.brackets() {
 5219                        if !enabled || !pair.close {
 5220                            continue;
 5221                        }
 5222
 5223                        if buffer.contains_str_at(selection.start, &pair.end) {
 5224                            let pair_start_len = pair.start.len();
 5225                            if buffer.contains_str_at(
 5226                                selection.start.saturating_sub_usize(pair_start_len),
 5227                                &pair.start,
 5228                            ) {
 5229                                selection.start -= pair_start_len;
 5230                                selection.end += pair.end.len();
 5231
 5232                                return selection;
 5233                            }
 5234                        }
 5235                    }
 5236                }
 5237
 5238                selection
 5239            })
 5240            .collect();
 5241
 5242        drop(buffer);
 5243        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5244            selections.select(new_selections)
 5245        });
 5246    }
 5247
 5248    /// Iterate the given selections, and for each one, find the smallest surrounding
 5249    /// autoclose region. This uses the ordering of the selections and the autoclose
 5250    /// regions to avoid repeated comparisons.
 5251    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5252        &'a self,
 5253        selections: impl IntoIterator<Item = Selection<D>>,
 5254        buffer: &'a MultiBufferSnapshot,
 5255    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5256        let mut i = 0;
 5257        let mut regions = self.autoclose_regions.as_slice();
 5258        selections.into_iter().map(move |selection| {
 5259            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5260
 5261            let mut enclosing = None;
 5262            while let Some(pair_state) = regions.get(i) {
 5263                if pair_state.range.end.to_offset(buffer) < range.start {
 5264                    regions = &regions[i + 1..];
 5265                    i = 0;
 5266                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5267                    break;
 5268                } else {
 5269                    if pair_state.selection_id == selection.id {
 5270                        enclosing = Some(pair_state);
 5271                    }
 5272                    i += 1;
 5273                }
 5274            }
 5275
 5276            (selection, enclosing)
 5277        })
 5278    }
 5279
 5280    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5281    fn invalidate_autoclose_regions(
 5282        &mut self,
 5283        mut selections: &[Selection<Anchor>],
 5284        buffer: &MultiBufferSnapshot,
 5285    ) {
 5286        self.autoclose_regions.retain(|state| {
 5287            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5288                return false;
 5289            }
 5290
 5291            let mut i = 0;
 5292            while let Some(selection) = selections.get(i) {
 5293                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5294                    selections = &selections[1..];
 5295                    continue;
 5296                }
 5297                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5298                    break;
 5299                }
 5300                if selection.id == state.selection_id {
 5301                    return true;
 5302                } else {
 5303                    i += 1;
 5304                }
 5305            }
 5306            false
 5307        });
 5308    }
 5309
 5310    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5311        let offset = position.to_offset(buffer);
 5312        let (word_range, kind) =
 5313            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5314        if offset > word_range.start && kind == Some(CharKind::Word) {
 5315            Some(
 5316                buffer
 5317                    .text_for_range(word_range.start..offset)
 5318                    .collect::<String>(),
 5319            )
 5320        } else {
 5321            None
 5322        }
 5323    }
 5324
 5325    pub fn visible_excerpts(
 5326        &self,
 5327        lsp_related_only: bool,
 5328        cx: &mut Context<Editor>,
 5329    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5330        let project = self.project().cloned();
 5331        let multi_buffer = self.buffer().read(cx);
 5332        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5333        let multi_buffer_visible_start = self
 5334            .scroll_manager
 5335            .anchor()
 5336            .anchor
 5337            .to_point(&multi_buffer_snapshot);
 5338        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5339            multi_buffer_visible_start
 5340                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5341            Bias::Left,
 5342        );
 5343        multi_buffer_snapshot
 5344            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5345            .into_iter()
 5346            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5347            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5348                if !lsp_related_only {
 5349                    return Some((
 5350                        excerpt_id,
 5351                        (
 5352                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5353                            buffer.version().clone(),
 5354                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5355                        ),
 5356                    ));
 5357                }
 5358
 5359                let project = project.as_ref()?.read(cx);
 5360                let buffer_file = project::File::from_dyn(buffer.file())?;
 5361                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5362                let worktree_entry = buffer_worktree
 5363                    .read(cx)
 5364                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5365                if worktree_entry.is_ignored {
 5366                    None
 5367                } else {
 5368                    Some((
 5369                        excerpt_id,
 5370                        (
 5371                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5372                            buffer.version().clone(),
 5373                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5374                        ),
 5375                    ))
 5376                }
 5377            })
 5378            .collect()
 5379    }
 5380
 5381    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5382        TextLayoutDetails {
 5383            text_system: window.text_system().clone(),
 5384            editor_style: self.style.clone().unwrap(),
 5385            rem_size: window.rem_size(),
 5386            scroll_anchor: self.scroll_manager.anchor(),
 5387            visible_rows: self.visible_line_count(),
 5388            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5389        }
 5390    }
 5391
 5392    fn trigger_on_type_formatting(
 5393        &self,
 5394        input: String,
 5395        window: &mut Window,
 5396        cx: &mut Context<Self>,
 5397    ) -> Option<Task<Result<()>>> {
 5398        if input.len() != 1 {
 5399            return None;
 5400        }
 5401
 5402        let project = self.project()?;
 5403        let position = self.selections.newest_anchor().head();
 5404        let (buffer, buffer_position) = self
 5405            .buffer
 5406            .read(cx)
 5407            .text_anchor_for_position(position, cx)?;
 5408
 5409        let settings = language_settings::language_settings(
 5410            buffer
 5411                .read(cx)
 5412                .language_at(buffer_position)
 5413                .map(|l| l.name()),
 5414            buffer.read(cx).file(),
 5415            cx,
 5416        );
 5417        if !settings.use_on_type_format {
 5418            return None;
 5419        }
 5420
 5421        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5422        // hence we do LSP request & edit on host side only — add formats to host's history.
 5423        let push_to_lsp_host_history = true;
 5424        // If this is not the host, append its history with new edits.
 5425        let push_to_client_history = project.read(cx).is_via_collab();
 5426
 5427        let on_type_formatting = project.update(cx, |project, cx| {
 5428            project.on_type_format(
 5429                buffer.clone(),
 5430                buffer_position,
 5431                input,
 5432                push_to_lsp_host_history,
 5433                cx,
 5434            )
 5435        });
 5436        Some(cx.spawn_in(window, async move |editor, cx| {
 5437            if let Some(transaction) = on_type_formatting.await? {
 5438                if push_to_client_history {
 5439                    buffer
 5440                        .update(cx, |buffer, _| {
 5441                            buffer.push_transaction(transaction, Instant::now());
 5442                            buffer.finalize_last_transaction();
 5443                        })
 5444                        .ok();
 5445                }
 5446                editor.update(cx, |editor, cx| {
 5447                    editor.refresh_document_highlights(cx);
 5448                })?;
 5449            }
 5450            Ok(())
 5451        }))
 5452    }
 5453
 5454    pub fn show_word_completions(
 5455        &mut self,
 5456        _: &ShowWordCompletions,
 5457        window: &mut Window,
 5458        cx: &mut Context<Self>,
 5459    ) {
 5460        self.open_or_update_completions_menu(
 5461            Some(CompletionsMenuSource::Words {
 5462                ignore_threshold: true,
 5463            }),
 5464            None,
 5465            false,
 5466            window,
 5467            cx,
 5468        );
 5469    }
 5470
 5471    pub fn show_completions(
 5472        &mut self,
 5473        _: &ShowCompletions,
 5474        window: &mut Window,
 5475        cx: &mut Context<Self>,
 5476    ) {
 5477        self.open_or_update_completions_menu(None, None, false, window, cx);
 5478    }
 5479
 5480    fn open_or_update_completions_menu(
 5481        &mut self,
 5482        requested_source: Option<CompletionsMenuSource>,
 5483        trigger: Option<String>,
 5484        trigger_in_words: bool,
 5485        window: &mut Window,
 5486        cx: &mut Context<Self>,
 5487    ) {
 5488        if self.pending_rename.is_some() {
 5489            return;
 5490        }
 5491
 5492        let completions_source = self
 5493            .context_menu
 5494            .borrow()
 5495            .as_ref()
 5496            .and_then(|menu| match menu {
 5497                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5498                CodeContextMenu::CodeActions(_) => None,
 5499            });
 5500
 5501        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5502
 5503        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5504        // inserted and selected. To handle that case, the start of the selection is used so that
 5505        // the menu starts with all choices.
 5506        let position = self
 5507            .selections
 5508            .newest_anchor()
 5509            .start
 5510            .bias_right(&multibuffer_snapshot);
 5511        if position.diff_base_anchor.is_some() {
 5512            return;
 5513        }
 5514        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5515        let Some(buffer) = buffer_position
 5516            .text_anchor
 5517            .buffer_id
 5518            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5519        else {
 5520            return;
 5521        };
 5522        let buffer_snapshot = buffer.read(cx).snapshot();
 5523
 5524        let menu_is_open = matches!(
 5525            self.context_menu.borrow().as_ref(),
 5526            Some(CodeContextMenu::Completions(_))
 5527        );
 5528
 5529        let language = buffer_snapshot
 5530            .language_at(buffer_position.text_anchor)
 5531            .map(|language| language.name());
 5532
 5533        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5534        let completion_settings = language_settings.completions.clone();
 5535
 5536        if !menu_is_open && trigger.is_some() && !language_settings.show_completions_on_input {
 5537            return;
 5538        }
 5539
 5540        let query: Option<Arc<String>> =
 5541            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5542                .map(|query| query.into());
 5543
 5544        drop(multibuffer_snapshot);
 5545
 5546        // Hide the current completions menu when query is empty. Without this, cached
 5547        // completions from before the trigger char may be reused (#32774).
 5548        if query.is_none() && menu_is_open {
 5549            self.hide_context_menu(window, cx);
 5550        }
 5551
 5552        let mut ignore_word_threshold = false;
 5553        let provider = match requested_source {
 5554            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5555            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5556                ignore_word_threshold = ignore_threshold;
 5557                None
 5558            }
 5559            Some(CompletionsMenuSource::SnippetChoices)
 5560            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5561                log::error!("bug: SnippetChoices requested_source is not handled");
 5562                None
 5563            }
 5564        };
 5565
 5566        let sort_completions = provider
 5567            .as_ref()
 5568            .is_some_and(|provider| provider.sort_completions());
 5569
 5570        let filter_completions = provider
 5571            .as_ref()
 5572            .is_none_or(|provider| provider.filter_completions());
 5573
 5574        let was_snippets_only = matches!(
 5575            completions_source,
 5576            Some(CompletionsMenuSource::SnippetsOnly)
 5577        );
 5578
 5579        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5580            if filter_completions {
 5581                menu.filter(
 5582                    query.clone().unwrap_or_default(),
 5583                    buffer_position.text_anchor,
 5584                    &buffer,
 5585                    provider.clone(),
 5586                    window,
 5587                    cx,
 5588                );
 5589            }
 5590            // When `is_incomplete` is false, no need to re-query completions when the current query
 5591            // is a suffix of the initial query.
 5592            let was_complete = !menu.is_incomplete;
 5593            if was_complete && !was_snippets_only {
 5594                // If the new query is a suffix of the old query (typing more characters) and
 5595                // the previous result was complete, the existing completions can be filtered.
 5596                //
 5597                // Note that snippet completions are always complete.
 5598                let query_matches = match (&menu.initial_query, &query) {
 5599                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5600                    (None, _) => true,
 5601                    _ => false,
 5602                };
 5603                if query_matches {
 5604                    let position_matches = if menu.initial_position == position {
 5605                        true
 5606                    } else {
 5607                        let snapshot = self.buffer.read(cx).read(cx);
 5608                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5609                    };
 5610                    if position_matches {
 5611                        return;
 5612                    }
 5613                }
 5614            }
 5615        };
 5616
 5617        let Anchor {
 5618            excerpt_id: buffer_excerpt_id,
 5619            text_anchor: buffer_position,
 5620            ..
 5621        } = buffer_position;
 5622
 5623        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5624            buffer_snapshot.surrounding_word(buffer_position, None)
 5625        {
 5626            let word_to_exclude = buffer_snapshot
 5627                .text_for_range(word_range.clone())
 5628                .collect::<String>();
 5629            (
 5630                buffer_snapshot.anchor_before(word_range.start)
 5631                    ..buffer_snapshot.anchor_after(buffer_position),
 5632                Some(word_to_exclude),
 5633            )
 5634        } else {
 5635            (buffer_position..buffer_position, None)
 5636        };
 5637
 5638        let show_completion_documentation = buffer_snapshot
 5639            .settings_at(buffer_position, cx)
 5640            .show_completion_documentation;
 5641
 5642        // The document can be large, so stay in reasonable bounds when searching for words,
 5643        // otherwise completion pop-up might be slow to appear.
 5644        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5645        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5646        let min_word_search = buffer_snapshot.clip_point(
 5647            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5648            Bias::Left,
 5649        );
 5650        let max_word_search = buffer_snapshot.clip_point(
 5651            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5652            Bias::Right,
 5653        );
 5654        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5655            ..buffer_snapshot.point_to_offset(max_word_search);
 5656
 5657        let skip_digits = query
 5658            .as_ref()
 5659            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5660
 5661        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5662            trigger.as_ref().is_none_or(|trigger| {
 5663                provider.is_completion_trigger(
 5664                    &buffer,
 5665                    position.text_anchor,
 5666                    trigger,
 5667                    trigger_in_words,
 5668                    cx,
 5669                )
 5670            })
 5671        });
 5672
 5673        let provider_responses = if let Some(provider) = &provider
 5674            && load_provider_completions
 5675        {
 5676            let trigger_character =
 5677                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5678            let completion_context = CompletionContext {
 5679                trigger_kind: match &trigger_character {
 5680                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5681                    None => CompletionTriggerKind::INVOKED,
 5682                },
 5683                trigger_character,
 5684            };
 5685
 5686            provider.completions(
 5687                buffer_excerpt_id,
 5688                &buffer,
 5689                buffer_position,
 5690                completion_context,
 5691                window,
 5692                cx,
 5693            )
 5694        } else {
 5695            Task::ready(Ok(Vec::new()))
 5696        };
 5697
 5698        let load_word_completions = if !self.word_completions_enabled {
 5699            false
 5700        } else if requested_source
 5701            == Some(CompletionsMenuSource::Words {
 5702                ignore_threshold: true,
 5703            })
 5704        {
 5705            true
 5706        } else {
 5707            load_provider_completions
 5708                && completion_settings.words != WordsCompletionMode::Disabled
 5709                && (ignore_word_threshold || {
 5710                    let words_min_length = completion_settings.words_min_length;
 5711                    // check whether word has at least `words_min_length` characters
 5712                    let query_chars = query.iter().flat_map(|q| q.chars());
 5713                    query_chars.take(words_min_length).count() == words_min_length
 5714                })
 5715        };
 5716
 5717        let mut words = if load_word_completions {
 5718            cx.background_spawn({
 5719                let buffer_snapshot = buffer_snapshot.clone();
 5720                async move {
 5721                    buffer_snapshot.words_in_range(WordsQuery {
 5722                        fuzzy_contents: None,
 5723                        range: word_search_range,
 5724                        skip_digits,
 5725                    })
 5726                }
 5727            })
 5728        } else {
 5729            Task::ready(BTreeMap::default())
 5730        };
 5731
 5732        let snippets = if let Some(provider) = &provider
 5733            && provider.show_snippets()
 5734            && let Some(project) = self.project()
 5735        {
 5736            let char_classifier = buffer_snapshot
 5737                .char_classifier_at(buffer_position)
 5738                .scope_context(Some(CharScopeContext::Completion));
 5739            project.update(cx, |project, cx| {
 5740                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5741            })
 5742        } else {
 5743            Task::ready(Ok(CompletionResponse {
 5744                completions: Vec::new(),
 5745                display_options: Default::default(),
 5746                is_incomplete: false,
 5747            }))
 5748        };
 5749
 5750        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5751
 5752        let id = post_inc(&mut self.next_completion_id);
 5753        let task = cx.spawn_in(window, async move |editor, cx| {
 5754            let Ok(()) = editor.update(cx, |this, _| {
 5755                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5756            }) else {
 5757                return;
 5758            };
 5759
 5760            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5761            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5762            let mut completions = Vec::new();
 5763            let mut is_incomplete = false;
 5764            let mut display_options: Option<CompletionDisplayOptions> = None;
 5765            if let Some(provider_responses) = provider_responses.await.log_err()
 5766                && !provider_responses.is_empty()
 5767            {
 5768                for response in provider_responses {
 5769                    completions.extend(response.completions);
 5770                    is_incomplete = is_incomplete || response.is_incomplete;
 5771                    match display_options.as_mut() {
 5772                        None => {
 5773                            display_options = Some(response.display_options);
 5774                        }
 5775                        Some(options) => options.merge(&response.display_options),
 5776                    }
 5777                }
 5778                if completion_settings.words == WordsCompletionMode::Fallback {
 5779                    words = Task::ready(BTreeMap::default());
 5780                }
 5781            }
 5782            let display_options = display_options.unwrap_or_default();
 5783
 5784            let mut words = words.await;
 5785            if let Some(word_to_exclude) = &word_to_exclude {
 5786                words.remove(word_to_exclude);
 5787            }
 5788            for lsp_completion in &completions {
 5789                words.remove(&lsp_completion.new_text);
 5790            }
 5791            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5792                replace_range: word_replace_range.clone(),
 5793                new_text: word.clone(),
 5794                label: CodeLabel::plain(word, None),
 5795                match_start: None,
 5796                snippet_deduplication_key: None,
 5797                icon_path: None,
 5798                documentation: None,
 5799                source: CompletionSource::BufferWord {
 5800                    word_range,
 5801                    resolved: false,
 5802                },
 5803                insert_text_mode: Some(InsertTextMode::AS_IS),
 5804                confirm: None,
 5805            }));
 5806
 5807            completions.extend(
 5808                snippets
 5809                    .await
 5810                    .into_iter()
 5811                    .flat_map(|response| response.completions),
 5812            );
 5813
 5814            let menu = if completions.is_empty() {
 5815                None
 5816            } else {
 5817                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5818                    let languages = editor
 5819                        .workspace
 5820                        .as_ref()
 5821                        .and_then(|(workspace, _)| workspace.upgrade())
 5822                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5823                    let menu = CompletionsMenu::new(
 5824                        id,
 5825                        requested_source.unwrap_or(if load_provider_completions {
 5826                            CompletionsMenuSource::Normal
 5827                        } else {
 5828                            CompletionsMenuSource::SnippetsOnly
 5829                        }),
 5830                        sort_completions,
 5831                        show_completion_documentation,
 5832                        position,
 5833                        query.clone(),
 5834                        is_incomplete,
 5835                        buffer.clone(),
 5836                        completions.into(),
 5837                        display_options,
 5838                        snippet_sort_order,
 5839                        languages,
 5840                        language,
 5841                        cx,
 5842                    );
 5843
 5844                    let query = if filter_completions { query } else { None };
 5845                    let matches_task = menu.do_async_filtering(
 5846                        query.unwrap_or_default(),
 5847                        buffer_position,
 5848                        &buffer,
 5849                        cx,
 5850                    );
 5851                    (menu, matches_task)
 5852                }) else {
 5853                    return;
 5854                };
 5855
 5856                let matches = matches_task.await;
 5857
 5858                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5859                    // Newer menu already set, so exit.
 5860                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5861                        editor.context_menu.borrow().as_ref()
 5862                        && prev_menu.id > id
 5863                    {
 5864                        return;
 5865                    };
 5866
 5867                    // Only valid to take prev_menu because either the new menu is immediately set
 5868                    // below, or the menu is hidden.
 5869                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5870                        editor.context_menu.borrow_mut().take()
 5871                    {
 5872                        let position_matches =
 5873                            if prev_menu.initial_position == menu.initial_position {
 5874                                true
 5875                            } else {
 5876                                let snapshot = editor.buffer.read(cx).read(cx);
 5877                                prev_menu.initial_position.to_offset(&snapshot)
 5878                                    == menu.initial_position.to_offset(&snapshot)
 5879                            };
 5880                        if position_matches {
 5881                            // Preserve markdown cache before `set_filter_results` because it will
 5882                            // try to populate the documentation cache.
 5883                            menu.preserve_markdown_cache(prev_menu);
 5884                        }
 5885                    };
 5886
 5887                    menu.set_filter_results(matches, provider, window, cx);
 5888                }) else {
 5889                    return;
 5890                };
 5891
 5892                menu.visible().then_some(menu)
 5893            };
 5894
 5895            editor
 5896                .update_in(cx, |editor, window, cx| {
 5897                    if editor.focus_handle.is_focused(window)
 5898                        && let Some(menu) = menu
 5899                    {
 5900                        *editor.context_menu.borrow_mut() =
 5901                            Some(CodeContextMenu::Completions(menu));
 5902
 5903                        crate::hover_popover::hide_hover(editor, cx);
 5904                        if editor.show_edit_predictions_in_menu() {
 5905                            editor.update_visible_edit_prediction(window, cx);
 5906                        } else {
 5907                            editor.discard_edit_prediction(false, cx);
 5908                        }
 5909
 5910                        cx.notify();
 5911                        return;
 5912                    }
 5913
 5914                    if editor.completion_tasks.len() <= 1 {
 5915                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5916                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5917                        // If it was already hidden and we don't show edit predictions in the menu,
 5918                        // we should also show the edit prediction when available.
 5919                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5920                            editor.update_visible_edit_prediction(window, cx);
 5921                        }
 5922                    }
 5923                })
 5924                .ok();
 5925        });
 5926
 5927        self.completion_tasks.push((id, task));
 5928    }
 5929
 5930    #[cfg(feature = "test-support")]
 5931    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5932        let menu = self.context_menu.borrow();
 5933        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5934            let completions = menu.completions.borrow();
 5935            Some(completions.to_vec())
 5936        } else {
 5937            None
 5938        }
 5939    }
 5940
 5941    pub fn with_completions_menu_matching_id<R>(
 5942        &self,
 5943        id: CompletionId,
 5944        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5945    ) -> R {
 5946        let mut context_menu = self.context_menu.borrow_mut();
 5947        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5948            return f(None);
 5949        };
 5950        if completions_menu.id != id {
 5951            return f(None);
 5952        }
 5953        f(Some(completions_menu))
 5954    }
 5955
 5956    pub fn confirm_completion(
 5957        &mut self,
 5958        action: &ConfirmCompletion,
 5959        window: &mut Window,
 5960        cx: &mut Context<Self>,
 5961    ) -> Option<Task<Result<()>>> {
 5962        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5963        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5964    }
 5965
 5966    pub fn confirm_completion_insert(
 5967        &mut self,
 5968        _: &ConfirmCompletionInsert,
 5969        window: &mut Window,
 5970        cx: &mut Context<Self>,
 5971    ) -> Option<Task<Result<()>>> {
 5972        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5973        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5974    }
 5975
 5976    pub fn confirm_completion_replace(
 5977        &mut self,
 5978        _: &ConfirmCompletionReplace,
 5979        window: &mut Window,
 5980        cx: &mut Context<Self>,
 5981    ) -> Option<Task<Result<()>>> {
 5982        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5983        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5984    }
 5985
 5986    pub fn compose_completion(
 5987        &mut self,
 5988        action: &ComposeCompletion,
 5989        window: &mut Window,
 5990        cx: &mut Context<Self>,
 5991    ) -> Option<Task<Result<()>>> {
 5992        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5993        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5994    }
 5995
 5996    fn do_completion(
 5997        &mut self,
 5998        item_ix: Option<usize>,
 5999        intent: CompletionIntent,
 6000        window: &mut Window,
 6001        cx: &mut Context<Editor>,
 6002    ) -> Option<Task<Result<()>>> {
 6003        use language::ToOffset as _;
 6004
 6005        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6006        else {
 6007            return None;
 6008        };
 6009
 6010        let candidate_id = {
 6011            let entries = completions_menu.entries.borrow();
 6012            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6013            if self.show_edit_predictions_in_menu() {
 6014                self.discard_edit_prediction(true, cx);
 6015            }
 6016            mat.candidate_id
 6017        };
 6018
 6019        let completion = completions_menu
 6020            .completions
 6021            .borrow()
 6022            .get(candidate_id)?
 6023            .clone();
 6024        cx.stop_propagation();
 6025
 6026        let buffer_handle = completions_menu.buffer.clone();
 6027
 6028        let CompletionEdit {
 6029            new_text,
 6030            snippet,
 6031            replace_range,
 6032        } = process_completion_for_edit(
 6033            &completion,
 6034            intent,
 6035            &buffer_handle,
 6036            &completions_menu.initial_position.text_anchor,
 6037            cx,
 6038        );
 6039
 6040        let buffer = buffer_handle.read(cx);
 6041        let snapshot = self.buffer.read(cx).snapshot(cx);
 6042        let newest_anchor = self.selections.newest_anchor();
 6043        let replace_range_multibuffer = {
 6044            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6045            excerpt.map_range_from_buffer(replace_range.clone())
 6046        };
 6047        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6048            return None;
 6049        }
 6050
 6051        let old_text = buffer
 6052            .text_for_range(replace_range.clone())
 6053            .collect::<String>();
 6054        let lookbehind = newest_anchor
 6055            .start
 6056            .text_anchor
 6057            .to_offset(buffer)
 6058            .saturating_sub(replace_range.start.0);
 6059        let lookahead = replace_range
 6060            .end
 6061            .0
 6062            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6063        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6064        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6065
 6066        let selections = self
 6067            .selections
 6068            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6069        let mut ranges = Vec::new();
 6070        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6071
 6072        for selection in &selections {
 6073            let range = if selection.id == newest_anchor.id {
 6074                replace_range_multibuffer.clone()
 6075            } else {
 6076                let mut range = selection.range();
 6077
 6078                // if prefix is present, don't duplicate it
 6079                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6080                    range.start = range.start.saturating_sub_usize(lookbehind);
 6081
 6082                    // if suffix is also present, mimic the newest cursor and replace it
 6083                    if selection.id != newest_anchor.id
 6084                        && snapshot.contains_str_at(range.end, suffix)
 6085                    {
 6086                        range.end += lookahead;
 6087                    }
 6088                }
 6089                range
 6090            };
 6091
 6092            ranges.push(range.clone());
 6093
 6094            if !self.linked_edit_ranges.is_empty() {
 6095                let start_anchor = snapshot.anchor_before(range.start);
 6096                let end_anchor = snapshot.anchor_after(range.end);
 6097                if let Some(ranges) = self
 6098                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6099                {
 6100                    for (buffer, edits) in ranges {
 6101                        linked_edits
 6102                            .entry(buffer.clone())
 6103                            .or_default()
 6104                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6105                    }
 6106                }
 6107            }
 6108        }
 6109
 6110        let common_prefix_len = old_text
 6111            .chars()
 6112            .zip(new_text.chars())
 6113            .take_while(|(a, b)| a == b)
 6114            .map(|(a, _)| a.len_utf8())
 6115            .sum::<usize>();
 6116
 6117        cx.emit(EditorEvent::InputHandled {
 6118            utf16_range_to_replace: None,
 6119            text: new_text[common_prefix_len..].into(),
 6120        });
 6121
 6122        self.transact(window, cx, |editor, window, cx| {
 6123            if let Some(mut snippet) = snippet {
 6124                snippet.text = new_text.to_string();
 6125                editor
 6126                    .insert_snippet(&ranges, snippet, window, cx)
 6127                    .log_err();
 6128            } else {
 6129                editor.buffer.update(cx, |multi_buffer, cx| {
 6130                    let auto_indent = match completion.insert_text_mode {
 6131                        Some(InsertTextMode::AS_IS) => None,
 6132                        _ => editor.autoindent_mode.clone(),
 6133                    };
 6134                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6135                    multi_buffer.edit(edits, auto_indent, cx);
 6136                });
 6137            }
 6138            for (buffer, edits) in linked_edits {
 6139                buffer.update(cx, |buffer, cx| {
 6140                    let snapshot = buffer.snapshot();
 6141                    let edits = edits
 6142                        .into_iter()
 6143                        .map(|(range, text)| {
 6144                            use text::ToPoint as TP;
 6145                            let end_point = TP::to_point(&range.end, &snapshot);
 6146                            let start_point = TP::to_point(&range.start, &snapshot);
 6147                            (start_point..end_point, text)
 6148                        })
 6149                        .sorted_by_key(|(range, _)| range.start);
 6150                    buffer.edit(edits, None, cx);
 6151                })
 6152            }
 6153
 6154            editor.refresh_edit_prediction(true, false, window, cx);
 6155        });
 6156        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6157
 6158        let show_new_completions_on_confirm = completion
 6159            .confirm
 6160            .as_ref()
 6161            .is_some_and(|confirm| confirm(intent, window, cx));
 6162        if show_new_completions_on_confirm {
 6163            self.open_or_update_completions_menu(None, None, false, window, cx);
 6164        }
 6165
 6166        let provider = self.completion_provider.as_ref()?;
 6167
 6168        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6169        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6170            let CompletionSource::Lsp {
 6171                lsp_completion,
 6172                server_id,
 6173                ..
 6174            } = &completion.source
 6175            else {
 6176                return None;
 6177            };
 6178            let lsp_command = lsp_completion.command.as_ref()?;
 6179            let available_commands = lsp_store
 6180                .read(cx)
 6181                .lsp_server_capabilities
 6182                .get(server_id)
 6183                .and_then(|server_capabilities| {
 6184                    server_capabilities
 6185                        .execute_command_provider
 6186                        .as_ref()
 6187                        .map(|options| options.commands.as_slice())
 6188                })?;
 6189            if available_commands.contains(&lsp_command.command) {
 6190                Some(CodeAction {
 6191                    server_id: *server_id,
 6192                    range: language::Anchor::MIN..language::Anchor::MIN,
 6193                    lsp_action: LspAction::Command(lsp_command.clone()),
 6194                    resolved: false,
 6195                })
 6196            } else {
 6197                None
 6198            }
 6199        });
 6200
 6201        drop(completion);
 6202        let apply_edits = provider.apply_additional_edits_for_completion(
 6203            buffer_handle.clone(),
 6204            completions_menu.completions.clone(),
 6205            candidate_id,
 6206            true,
 6207            cx,
 6208        );
 6209
 6210        let editor_settings = EditorSettings::get_global(cx);
 6211        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6212            // After the code completion is finished, users often want to know what signatures are needed.
 6213            // so we should automatically call signature_help
 6214            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6215        }
 6216
 6217        Some(cx.spawn_in(window, async move |editor, cx| {
 6218            apply_edits.await?;
 6219
 6220            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6221                let title = command.lsp_action.title().to_owned();
 6222                let project_transaction = lsp_store
 6223                    .update(cx, |lsp_store, cx| {
 6224                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6225                    })?
 6226                    .await
 6227                    .context("applying post-completion command")?;
 6228                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6229                    Self::open_project_transaction(
 6230                        &editor,
 6231                        workspace.downgrade(),
 6232                        project_transaction,
 6233                        title,
 6234                        cx,
 6235                    )
 6236                    .await?;
 6237                }
 6238            }
 6239
 6240            Ok(())
 6241        }))
 6242    }
 6243
 6244    pub fn toggle_code_actions(
 6245        &mut self,
 6246        action: &ToggleCodeActions,
 6247        window: &mut Window,
 6248        cx: &mut Context<Self>,
 6249    ) {
 6250        let quick_launch = action.quick_launch;
 6251        let mut context_menu = self.context_menu.borrow_mut();
 6252        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6253            if code_actions.deployed_from == action.deployed_from {
 6254                // Toggle if we're selecting the same one
 6255                *context_menu = None;
 6256                cx.notify();
 6257                return;
 6258            } else {
 6259                // Otherwise, clear it and start a new one
 6260                *context_menu = None;
 6261                cx.notify();
 6262            }
 6263        }
 6264        drop(context_menu);
 6265        let snapshot = self.snapshot(window, cx);
 6266        let deployed_from = action.deployed_from.clone();
 6267        let action = action.clone();
 6268        self.completion_tasks.clear();
 6269        self.discard_edit_prediction(false, cx);
 6270
 6271        let multibuffer_point = match &action.deployed_from {
 6272            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6273                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6274            }
 6275            _ => self
 6276                .selections
 6277                .newest::<Point>(&snapshot.display_snapshot)
 6278                .head(),
 6279        };
 6280        let Some((buffer, buffer_row)) = snapshot
 6281            .buffer_snapshot()
 6282            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6283            .and_then(|(buffer_snapshot, range)| {
 6284                self.buffer()
 6285                    .read(cx)
 6286                    .buffer(buffer_snapshot.remote_id())
 6287                    .map(|buffer| (buffer, range.start.row))
 6288            })
 6289        else {
 6290            return;
 6291        };
 6292        let buffer_id = buffer.read(cx).remote_id();
 6293        let tasks = self
 6294            .tasks
 6295            .get(&(buffer_id, buffer_row))
 6296            .map(|t| Arc::new(t.to_owned()));
 6297
 6298        if !self.focus_handle.is_focused(window) {
 6299            return;
 6300        }
 6301        let project = self.project.clone();
 6302
 6303        let code_actions_task = match deployed_from {
 6304            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6305            _ => self.code_actions(buffer_row, window, cx),
 6306        };
 6307
 6308        let runnable_task = match deployed_from {
 6309            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6310            _ => {
 6311                let mut task_context_task = Task::ready(None);
 6312                if let Some(tasks) = &tasks
 6313                    && let Some(project) = project
 6314                {
 6315                    task_context_task =
 6316                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6317                }
 6318
 6319                cx.spawn_in(window, {
 6320                    let buffer = buffer.clone();
 6321                    async move |editor, cx| {
 6322                        let task_context = task_context_task.await;
 6323
 6324                        let resolved_tasks =
 6325                            tasks
 6326                                .zip(task_context.clone())
 6327                                .map(|(tasks, task_context)| ResolvedTasks {
 6328                                    templates: tasks.resolve(&task_context).collect(),
 6329                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6330                                        multibuffer_point.row,
 6331                                        tasks.column,
 6332                                    )),
 6333                                });
 6334                        let debug_scenarios = editor
 6335                            .update(cx, |editor, cx| {
 6336                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6337                            })?
 6338                            .await;
 6339                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6340                    }
 6341                })
 6342            }
 6343        };
 6344
 6345        cx.spawn_in(window, async move |editor, cx| {
 6346            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6347            let code_actions = code_actions_task.await;
 6348            let spawn_straight_away = quick_launch
 6349                && resolved_tasks
 6350                    .as_ref()
 6351                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6352                && code_actions
 6353                    .as_ref()
 6354                    .is_none_or(|actions| actions.is_empty())
 6355                && debug_scenarios.is_empty();
 6356
 6357            editor.update_in(cx, |editor, window, cx| {
 6358                crate::hover_popover::hide_hover(editor, cx);
 6359                let actions = CodeActionContents::new(
 6360                    resolved_tasks,
 6361                    code_actions,
 6362                    debug_scenarios,
 6363                    task_context.unwrap_or_default(),
 6364                );
 6365
 6366                // Don't show the menu if there are no actions available
 6367                if actions.is_empty() {
 6368                    cx.notify();
 6369                    return Task::ready(Ok(()));
 6370                }
 6371
 6372                *editor.context_menu.borrow_mut() =
 6373                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6374                        buffer,
 6375                        actions,
 6376                        selected_item: Default::default(),
 6377                        scroll_handle: UniformListScrollHandle::default(),
 6378                        deployed_from,
 6379                    }));
 6380                cx.notify();
 6381                if spawn_straight_away
 6382                    && let Some(task) = editor.confirm_code_action(
 6383                        &ConfirmCodeAction { item_ix: Some(0) },
 6384                        window,
 6385                        cx,
 6386                    )
 6387                {
 6388                    return task;
 6389                }
 6390
 6391                Task::ready(Ok(()))
 6392            })
 6393        })
 6394        .detach_and_log_err(cx);
 6395    }
 6396
 6397    fn debug_scenarios(
 6398        &mut self,
 6399        resolved_tasks: &Option<ResolvedTasks>,
 6400        buffer: &Entity<Buffer>,
 6401        cx: &mut App,
 6402    ) -> Task<Vec<task::DebugScenario>> {
 6403        maybe!({
 6404            let project = self.project()?;
 6405            let dap_store = project.read(cx).dap_store();
 6406            let mut scenarios = vec![];
 6407            let resolved_tasks = resolved_tasks.as_ref()?;
 6408            let buffer = buffer.read(cx);
 6409            let language = buffer.language()?;
 6410            let file = buffer.file();
 6411            let debug_adapter = language_settings(language.name().into(), file, cx)
 6412                .debuggers
 6413                .first()
 6414                .map(SharedString::from)
 6415                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6416
 6417            dap_store.update(cx, |dap_store, cx| {
 6418                for (_, task) in &resolved_tasks.templates {
 6419                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6420                        task.original_task().clone(),
 6421                        debug_adapter.clone().into(),
 6422                        task.display_label().to_owned().into(),
 6423                        cx,
 6424                    );
 6425                    scenarios.push(maybe_scenario);
 6426                }
 6427            });
 6428            Some(cx.background_spawn(async move {
 6429                futures::future::join_all(scenarios)
 6430                    .await
 6431                    .into_iter()
 6432                    .flatten()
 6433                    .collect::<Vec<_>>()
 6434            }))
 6435        })
 6436        .unwrap_or_else(|| Task::ready(vec![]))
 6437    }
 6438
 6439    fn code_actions(
 6440        &mut self,
 6441        buffer_row: u32,
 6442        window: &mut Window,
 6443        cx: &mut Context<Self>,
 6444    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6445        let mut task = self.code_actions_task.take();
 6446        cx.spawn_in(window, async move |editor, cx| {
 6447            while let Some(prev_task) = task {
 6448                prev_task.await.log_err();
 6449                task = editor
 6450                    .update(cx, |this, _| this.code_actions_task.take())
 6451                    .ok()?;
 6452            }
 6453
 6454            editor
 6455                .update(cx, |editor, cx| {
 6456                    editor
 6457                        .available_code_actions
 6458                        .clone()
 6459                        .and_then(|(location, code_actions)| {
 6460                            let snapshot = location.buffer.read(cx).snapshot();
 6461                            let point_range = location.range.to_point(&snapshot);
 6462                            let point_range = point_range.start.row..=point_range.end.row;
 6463                            if point_range.contains(&buffer_row) {
 6464                                Some(code_actions)
 6465                            } else {
 6466                                None
 6467                            }
 6468                        })
 6469                })
 6470                .ok()
 6471                .flatten()
 6472        })
 6473    }
 6474
 6475    pub fn confirm_code_action(
 6476        &mut self,
 6477        action: &ConfirmCodeAction,
 6478        window: &mut Window,
 6479        cx: &mut Context<Self>,
 6480    ) -> Option<Task<Result<()>>> {
 6481        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6482
 6483        let actions_menu =
 6484            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6485                menu
 6486            } else {
 6487                return None;
 6488            };
 6489
 6490        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6491        let action = actions_menu.actions.get(action_ix)?;
 6492        let title = action.label();
 6493        let buffer = actions_menu.buffer;
 6494        let workspace = self.workspace()?;
 6495
 6496        match action {
 6497            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6498                workspace.update(cx, |workspace, cx| {
 6499                    workspace.schedule_resolved_task(
 6500                        task_source_kind,
 6501                        resolved_task,
 6502                        false,
 6503                        window,
 6504                        cx,
 6505                    );
 6506
 6507                    Some(Task::ready(Ok(())))
 6508                })
 6509            }
 6510            CodeActionsItem::CodeAction {
 6511                excerpt_id,
 6512                action,
 6513                provider,
 6514            } => {
 6515                let apply_code_action =
 6516                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6517                let workspace = workspace.downgrade();
 6518                Some(cx.spawn_in(window, async move |editor, cx| {
 6519                    let project_transaction = apply_code_action.await?;
 6520                    Self::open_project_transaction(
 6521                        &editor,
 6522                        workspace,
 6523                        project_transaction,
 6524                        title,
 6525                        cx,
 6526                    )
 6527                    .await
 6528                }))
 6529            }
 6530            CodeActionsItem::DebugScenario(scenario) => {
 6531                let context = actions_menu.actions.context;
 6532
 6533                workspace.update(cx, |workspace, cx| {
 6534                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6535                    workspace.start_debug_session(
 6536                        scenario,
 6537                        context,
 6538                        Some(buffer),
 6539                        None,
 6540                        window,
 6541                        cx,
 6542                    );
 6543                });
 6544                Some(Task::ready(Ok(())))
 6545            }
 6546        }
 6547    }
 6548
 6549    pub async fn open_project_transaction(
 6550        editor: &WeakEntity<Editor>,
 6551        workspace: WeakEntity<Workspace>,
 6552        transaction: ProjectTransaction,
 6553        title: String,
 6554        cx: &mut AsyncWindowContext,
 6555    ) -> Result<()> {
 6556        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6557        cx.update(|_, cx| {
 6558            entries.sort_unstable_by_key(|(buffer, _)| {
 6559                buffer.read(cx).file().map(|f| f.path().clone())
 6560            });
 6561        })?;
 6562        if entries.is_empty() {
 6563            return Ok(());
 6564        }
 6565
 6566        // If the project transaction's edits are all contained within this editor, then
 6567        // avoid opening a new editor to display them.
 6568
 6569        if let [(buffer, transaction)] = &*entries {
 6570            let excerpt = editor.update(cx, |editor, cx| {
 6571                editor
 6572                    .buffer()
 6573                    .read(cx)
 6574                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6575            })?;
 6576            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6577                && excerpted_buffer == *buffer
 6578            {
 6579                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6580                    let excerpt_range = excerpt_range.to_offset(buffer);
 6581                    buffer
 6582                        .edited_ranges_for_transaction::<usize>(transaction)
 6583                        .all(|range| {
 6584                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6585                        })
 6586                })?;
 6587
 6588                if all_edits_within_excerpt {
 6589                    return Ok(());
 6590                }
 6591            }
 6592        }
 6593
 6594        let mut ranges_to_highlight = Vec::new();
 6595        let excerpt_buffer = cx.new(|cx| {
 6596            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6597            for (buffer_handle, transaction) in &entries {
 6598                let edited_ranges = buffer_handle
 6599                    .read(cx)
 6600                    .edited_ranges_for_transaction::<Point>(transaction)
 6601                    .collect::<Vec<_>>();
 6602                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6603                    PathKey::for_buffer(buffer_handle, cx),
 6604                    buffer_handle.clone(),
 6605                    edited_ranges,
 6606                    multibuffer_context_lines(cx),
 6607                    cx,
 6608                );
 6609
 6610                ranges_to_highlight.extend(ranges);
 6611            }
 6612            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6613            multibuffer
 6614        })?;
 6615
 6616        workspace.update_in(cx, |workspace, window, cx| {
 6617            let project = workspace.project().clone();
 6618            let editor =
 6619                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6620            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6621            editor.update(cx, |editor, cx| {
 6622                editor.highlight_background::<Self>(
 6623                    &ranges_to_highlight,
 6624                    |_, theme| theme.colors().editor_highlighted_line_background,
 6625                    cx,
 6626                );
 6627            });
 6628        })?;
 6629
 6630        Ok(())
 6631    }
 6632
 6633    pub fn clear_code_action_providers(&mut self) {
 6634        self.code_action_providers.clear();
 6635        self.available_code_actions.take();
 6636    }
 6637
 6638    pub fn add_code_action_provider(
 6639        &mut self,
 6640        provider: Rc<dyn CodeActionProvider>,
 6641        window: &mut Window,
 6642        cx: &mut Context<Self>,
 6643    ) {
 6644        if self
 6645            .code_action_providers
 6646            .iter()
 6647            .any(|existing_provider| existing_provider.id() == provider.id())
 6648        {
 6649            return;
 6650        }
 6651
 6652        self.code_action_providers.push(provider);
 6653        self.refresh_code_actions(window, cx);
 6654    }
 6655
 6656    pub fn remove_code_action_provider(
 6657        &mut self,
 6658        id: Arc<str>,
 6659        window: &mut Window,
 6660        cx: &mut Context<Self>,
 6661    ) {
 6662        self.code_action_providers
 6663            .retain(|provider| provider.id() != id);
 6664        self.refresh_code_actions(window, cx);
 6665    }
 6666
 6667    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6668        !self.code_action_providers.is_empty()
 6669            && EditorSettings::get_global(cx).toolbar.code_actions
 6670    }
 6671
 6672    pub fn has_available_code_actions(&self) -> bool {
 6673        self.available_code_actions
 6674            .as_ref()
 6675            .is_some_and(|(_, actions)| !actions.is_empty())
 6676    }
 6677
 6678    fn render_inline_code_actions(
 6679        &self,
 6680        icon_size: ui::IconSize,
 6681        display_row: DisplayRow,
 6682        is_active: bool,
 6683        cx: &mut Context<Self>,
 6684    ) -> AnyElement {
 6685        let show_tooltip = !self.context_menu_visible();
 6686        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6687            .icon_size(icon_size)
 6688            .shape(ui::IconButtonShape::Square)
 6689            .icon_color(ui::Color::Hidden)
 6690            .toggle_state(is_active)
 6691            .when(show_tooltip, |this| {
 6692                this.tooltip({
 6693                    let focus_handle = self.focus_handle.clone();
 6694                    move |_window, cx| {
 6695                        Tooltip::for_action_in(
 6696                            "Toggle Code Actions",
 6697                            &ToggleCodeActions {
 6698                                deployed_from: None,
 6699                                quick_launch: false,
 6700                            },
 6701                            &focus_handle,
 6702                            cx,
 6703                        )
 6704                    }
 6705                })
 6706            })
 6707            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6708                window.focus(&editor.focus_handle(cx));
 6709                editor.toggle_code_actions(
 6710                    &crate::actions::ToggleCodeActions {
 6711                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6712                            display_row,
 6713                        )),
 6714                        quick_launch: false,
 6715                    },
 6716                    window,
 6717                    cx,
 6718                );
 6719            }))
 6720            .into_any_element()
 6721    }
 6722
 6723    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6724        &self.context_menu
 6725    }
 6726
 6727    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6728        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6729            cx.background_executor()
 6730                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6731                .await;
 6732
 6733            let (start_buffer, start, _, end, newest_selection) = this
 6734                .update(cx, |this, cx| {
 6735                    let newest_selection = this.selections.newest_anchor().clone();
 6736                    if newest_selection.head().diff_base_anchor.is_some() {
 6737                        return None;
 6738                    }
 6739                    let display_snapshot = this.display_snapshot(cx);
 6740                    let newest_selection_adjusted =
 6741                        this.selections.newest_adjusted(&display_snapshot);
 6742                    let buffer = this.buffer.read(cx);
 6743
 6744                    let (start_buffer, start) =
 6745                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6746                    let (end_buffer, end) =
 6747                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6748
 6749                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6750                })?
 6751                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6752                .context(
 6753                    "Expected selection to lie in a single buffer when refreshing code actions",
 6754                )?;
 6755            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6756                let providers = this.code_action_providers.clone();
 6757                let tasks = this
 6758                    .code_action_providers
 6759                    .iter()
 6760                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6761                    .collect::<Vec<_>>();
 6762                (providers, tasks)
 6763            })?;
 6764
 6765            let mut actions = Vec::new();
 6766            for (provider, provider_actions) in
 6767                providers.into_iter().zip(future::join_all(tasks).await)
 6768            {
 6769                if let Some(provider_actions) = provider_actions.log_err() {
 6770                    actions.extend(provider_actions.into_iter().map(|action| {
 6771                        AvailableCodeAction {
 6772                            excerpt_id: newest_selection.start.excerpt_id,
 6773                            action,
 6774                            provider: provider.clone(),
 6775                        }
 6776                    }));
 6777                }
 6778            }
 6779
 6780            this.update(cx, |this, cx| {
 6781                this.available_code_actions = if actions.is_empty() {
 6782                    None
 6783                } else {
 6784                    Some((
 6785                        Location {
 6786                            buffer: start_buffer,
 6787                            range: start..end,
 6788                        },
 6789                        actions.into(),
 6790                    ))
 6791                };
 6792                cx.notify();
 6793            })
 6794        }));
 6795    }
 6796
 6797    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6798        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6799            self.show_git_blame_inline = false;
 6800
 6801            self.show_git_blame_inline_delay_task =
 6802                Some(cx.spawn_in(window, async move |this, cx| {
 6803                    cx.background_executor().timer(delay).await;
 6804
 6805                    this.update(cx, |this, cx| {
 6806                        this.show_git_blame_inline = true;
 6807                        cx.notify();
 6808                    })
 6809                    .log_err();
 6810                }));
 6811        }
 6812    }
 6813
 6814    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6815        let snapshot = self.snapshot(window, cx);
 6816        let cursor = self
 6817            .selections
 6818            .newest::<Point>(&snapshot.display_snapshot)
 6819            .head();
 6820        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6821        else {
 6822            return;
 6823        };
 6824
 6825        if self.blame.is_none() {
 6826            self.start_git_blame(true, window, cx);
 6827        }
 6828        let Some(blame) = self.blame.as_ref() else {
 6829            return;
 6830        };
 6831
 6832        let row_info = RowInfo {
 6833            buffer_id: Some(buffer.remote_id()),
 6834            buffer_row: Some(point.row),
 6835            ..Default::default()
 6836        };
 6837        let Some((buffer, blame_entry)) = blame
 6838            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6839            .flatten()
 6840        else {
 6841            return;
 6842        };
 6843
 6844        let anchor = self.selections.newest_anchor().head();
 6845        let position = self.to_pixel_point(anchor, &snapshot, window);
 6846        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6847            self.show_blame_popover(
 6848                buffer,
 6849                &blame_entry,
 6850                position + last_bounds.origin,
 6851                true,
 6852                cx,
 6853            );
 6854        };
 6855    }
 6856
 6857    fn show_blame_popover(
 6858        &mut self,
 6859        buffer: BufferId,
 6860        blame_entry: &BlameEntry,
 6861        position: gpui::Point<Pixels>,
 6862        ignore_timeout: bool,
 6863        cx: &mut Context<Self>,
 6864    ) {
 6865        if let Some(state) = &mut self.inline_blame_popover {
 6866            state.hide_task.take();
 6867        } else {
 6868            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6869            let blame_entry = blame_entry.clone();
 6870            let show_task = cx.spawn(async move |editor, cx| {
 6871                if !ignore_timeout {
 6872                    cx.background_executor()
 6873                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6874                        .await;
 6875                }
 6876                editor
 6877                    .update(cx, |editor, cx| {
 6878                        editor.inline_blame_popover_show_task.take();
 6879                        let Some(blame) = editor.blame.as_ref() else {
 6880                            return;
 6881                        };
 6882                        let blame = blame.read(cx);
 6883                        let details = blame.details_for_entry(buffer, &blame_entry);
 6884                        let markdown = cx.new(|cx| {
 6885                            Markdown::new(
 6886                                details
 6887                                    .as_ref()
 6888                                    .map(|message| message.message.clone())
 6889                                    .unwrap_or_default(),
 6890                                None,
 6891                                None,
 6892                                cx,
 6893                            )
 6894                        });
 6895                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6896                            position,
 6897                            hide_task: None,
 6898                            popover_bounds: None,
 6899                            popover_state: InlineBlamePopoverState {
 6900                                scroll_handle: ScrollHandle::new(),
 6901                                commit_message: details,
 6902                                markdown,
 6903                            },
 6904                            keyboard_grace: ignore_timeout,
 6905                        });
 6906                        cx.notify();
 6907                    })
 6908                    .ok();
 6909            });
 6910            self.inline_blame_popover_show_task = Some(show_task);
 6911        }
 6912    }
 6913
 6914    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6915        self.inline_blame_popover_show_task.take();
 6916        if let Some(state) = &mut self.inline_blame_popover {
 6917            let hide_task = cx.spawn(async move |editor, cx| {
 6918                if !ignore_timeout {
 6919                    cx.background_executor()
 6920                        .timer(std::time::Duration::from_millis(100))
 6921                        .await;
 6922                }
 6923                editor
 6924                    .update(cx, |editor, cx| {
 6925                        editor.inline_blame_popover.take();
 6926                        cx.notify();
 6927                    })
 6928                    .ok();
 6929            });
 6930            state.hide_task = Some(hide_task);
 6931            true
 6932        } else {
 6933            false
 6934        }
 6935    }
 6936
 6937    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6938        if self.pending_rename.is_some() {
 6939            return None;
 6940        }
 6941
 6942        let provider = self.semantics_provider.clone()?;
 6943        let buffer = self.buffer.read(cx);
 6944        let newest_selection = self.selections.newest_anchor().clone();
 6945        let cursor_position = newest_selection.head();
 6946        let (cursor_buffer, cursor_buffer_position) =
 6947            buffer.text_anchor_for_position(cursor_position, cx)?;
 6948        let (tail_buffer, tail_buffer_position) =
 6949            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6950        if cursor_buffer != tail_buffer {
 6951            return None;
 6952        }
 6953
 6954        let snapshot = cursor_buffer.read(cx).snapshot();
 6955        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6956        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6957        if start_word_range != end_word_range {
 6958            self.document_highlights_task.take();
 6959            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6960            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6961            return None;
 6962        }
 6963
 6964        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6965        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6966            cx.background_executor()
 6967                .timer(Duration::from_millis(debounce))
 6968                .await;
 6969
 6970            let highlights = if let Some(highlights) = cx
 6971                .update(|cx| {
 6972                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6973                })
 6974                .ok()
 6975                .flatten()
 6976            {
 6977                highlights.await.log_err()
 6978            } else {
 6979                None
 6980            };
 6981
 6982            if let Some(highlights) = highlights {
 6983                this.update(cx, |this, cx| {
 6984                    if this.pending_rename.is_some() {
 6985                        return;
 6986                    }
 6987
 6988                    let buffer = this.buffer.read(cx);
 6989                    if buffer
 6990                        .text_anchor_for_position(cursor_position, cx)
 6991                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6992                    {
 6993                        return;
 6994                    }
 6995
 6996                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6997                    let mut write_ranges = Vec::new();
 6998                    let mut read_ranges = Vec::new();
 6999                    for highlight in highlights {
 7000                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7001                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7002                        {
 7003                            let start = highlight
 7004                                .range
 7005                                .start
 7006                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7007                            let end = highlight
 7008                                .range
 7009                                .end
 7010                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7011                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7012                                continue;
 7013                            }
 7014
 7015                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7016                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7017                                write_ranges.push(range);
 7018                            } else {
 7019                                read_ranges.push(range);
 7020                            }
 7021                        }
 7022                    }
 7023
 7024                    this.highlight_background::<DocumentHighlightRead>(
 7025                        &read_ranges,
 7026                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7027                        cx,
 7028                    );
 7029                    this.highlight_background::<DocumentHighlightWrite>(
 7030                        &write_ranges,
 7031                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7032                        cx,
 7033                    );
 7034                    cx.notify();
 7035                })
 7036                .log_err();
 7037            }
 7038        }));
 7039        None
 7040    }
 7041
 7042    fn prepare_highlight_query_from_selection(
 7043        &mut self,
 7044        window: &Window,
 7045        cx: &mut Context<Editor>,
 7046    ) -> Option<(String, Range<Anchor>)> {
 7047        if matches!(self.mode, EditorMode::SingleLine) {
 7048            return None;
 7049        }
 7050        if !EditorSettings::get_global(cx).selection_highlight {
 7051            return None;
 7052        }
 7053        if self.selections.count() != 1 || self.selections.line_mode() {
 7054            return None;
 7055        }
 7056        let snapshot = self.snapshot(window, cx);
 7057        let selection = self.selections.newest::<Point>(&snapshot);
 7058        // If the selection spans multiple rows OR it is empty
 7059        if selection.start.row != selection.end.row
 7060            || selection.start.column == selection.end.column
 7061        {
 7062            return None;
 7063        }
 7064        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7065        let query = snapshot
 7066            .buffer_snapshot()
 7067            .text_for_range(selection_anchor_range.clone())
 7068            .collect::<String>();
 7069        if query.trim().is_empty() {
 7070            return None;
 7071        }
 7072        Some((query, selection_anchor_range))
 7073    }
 7074
 7075    fn update_selection_occurrence_highlights(
 7076        &mut self,
 7077        query_text: String,
 7078        query_range: Range<Anchor>,
 7079        multi_buffer_range_to_query: Range<Point>,
 7080        use_debounce: bool,
 7081        window: &mut Window,
 7082        cx: &mut Context<Editor>,
 7083    ) -> Task<()> {
 7084        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7085        cx.spawn_in(window, async move |editor, cx| {
 7086            if use_debounce {
 7087                cx.background_executor()
 7088                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7089                    .await;
 7090            }
 7091            let match_task = cx.background_spawn(async move {
 7092                let buffer_ranges = multi_buffer_snapshot
 7093                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7094                    .into_iter()
 7095                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7096                let mut match_ranges = Vec::new();
 7097                let Ok(regex) = project::search::SearchQuery::text(
 7098                    query_text.clone(),
 7099                    false,
 7100                    false,
 7101                    false,
 7102                    Default::default(),
 7103                    Default::default(),
 7104                    false,
 7105                    None,
 7106                ) else {
 7107                    return Vec::default();
 7108                };
 7109                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7110                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7111                    match_ranges.extend(
 7112                        regex
 7113                            .search(
 7114                                buffer_snapshot,
 7115                                Some(search_range.start.0..search_range.end.0),
 7116                            )
 7117                            .await
 7118                            .into_iter()
 7119                            .filter_map(|match_range| {
 7120                                let match_start = buffer_snapshot
 7121                                    .anchor_after(search_range.start + match_range.start);
 7122                                let match_end = buffer_snapshot
 7123                                    .anchor_before(search_range.start + match_range.end);
 7124                                let match_anchor_range =
 7125                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7126                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7127                            }),
 7128                    );
 7129                }
 7130                match_ranges
 7131            });
 7132            let match_ranges = match_task.await;
 7133            editor
 7134                .update_in(cx, |editor, _, cx| {
 7135                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7136                    if !match_ranges.is_empty() {
 7137                        editor.highlight_background::<SelectedTextHighlight>(
 7138                            &match_ranges,
 7139                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7140                            cx,
 7141                        )
 7142                    }
 7143                })
 7144                .log_err();
 7145        })
 7146    }
 7147
 7148    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7149        struct NewlineFold;
 7150        let type_id = std::any::TypeId::of::<NewlineFold>();
 7151        if !self.mode.is_single_line() {
 7152            return;
 7153        }
 7154        let snapshot = self.snapshot(window, cx);
 7155        if snapshot.buffer_snapshot().max_point().row == 0 {
 7156            return;
 7157        }
 7158        let task = cx.background_spawn(async move {
 7159            let new_newlines = snapshot
 7160                .buffer_chars_at(MultiBufferOffset(0))
 7161                .filter_map(|(c, i)| {
 7162                    if c == '\n' {
 7163                        Some(
 7164                            snapshot.buffer_snapshot().anchor_after(i)
 7165                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7166                        )
 7167                    } else {
 7168                        None
 7169                    }
 7170                })
 7171                .collect::<Vec<_>>();
 7172            let existing_newlines = snapshot
 7173                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7174                .filter_map(|fold| {
 7175                    if fold.placeholder.type_tag == Some(type_id) {
 7176                        Some(fold.range.start..fold.range.end)
 7177                    } else {
 7178                        None
 7179                    }
 7180                })
 7181                .collect::<Vec<_>>();
 7182
 7183            (new_newlines, existing_newlines)
 7184        });
 7185        self.folding_newlines = cx.spawn(async move |this, cx| {
 7186            let (new_newlines, existing_newlines) = task.await;
 7187            if new_newlines == existing_newlines {
 7188                return;
 7189            }
 7190            let placeholder = FoldPlaceholder {
 7191                render: Arc::new(move |_, _, cx| {
 7192                    div()
 7193                        .bg(cx.theme().status().hint_background)
 7194                        .border_b_1()
 7195                        .size_full()
 7196                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7197                        .border_color(cx.theme().status().hint)
 7198                        .child("\\n")
 7199                        .into_any()
 7200                }),
 7201                constrain_width: false,
 7202                merge_adjacent: false,
 7203                type_tag: Some(type_id),
 7204            };
 7205            let creases = new_newlines
 7206                .into_iter()
 7207                .map(|range| Crease::simple(range, placeholder.clone()))
 7208                .collect();
 7209            this.update(cx, |this, cx| {
 7210                this.display_map.update(cx, |display_map, cx| {
 7211                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7212                    display_map.fold(creases, cx);
 7213                });
 7214            })
 7215            .ok();
 7216        });
 7217    }
 7218
 7219    fn refresh_selected_text_highlights(
 7220        &mut self,
 7221        on_buffer_edit: bool,
 7222        window: &mut Window,
 7223        cx: &mut Context<Editor>,
 7224    ) {
 7225        let Some((query_text, query_range)) =
 7226            self.prepare_highlight_query_from_selection(window, cx)
 7227        else {
 7228            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7229            self.quick_selection_highlight_task.take();
 7230            self.debounced_selection_highlight_task.take();
 7231            return;
 7232        };
 7233        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7234        if on_buffer_edit
 7235            || self
 7236                .quick_selection_highlight_task
 7237                .as_ref()
 7238                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7239        {
 7240            let multi_buffer_visible_start = self
 7241                .scroll_manager
 7242                .anchor()
 7243                .anchor
 7244                .to_point(&multi_buffer_snapshot);
 7245            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7246                multi_buffer_visible_start
 7247                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7248                Bias::Left,
 7249            );
 7250            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7251            self.quick_selection_highlight_task = Some((
 7252                query_range.clone(),
 7253                self.update_selection_occurrence_highlights(
 7254                    query_text.clone(),
 7255                    query_range.clone(),
 7256                    multi_buffer_visible_range,
 7257                    false,
 7258                    window,
 7259                    cx,
 7260                ),
 7261            ));
 7262        }
 7263        if on_buffer_edit
 7264            || self
 7265                .debounced_selection_highlight_task
 7266                .as_ref()
 7267                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7268        {
 7269            let multi_buffer_start = multi_buffer_snapshot
 7270                .anchor_before(MultiBufferOffset(0))
 7271                .to_point(&multi_buffer_snapshot);
 7272            let multi_buffer_end = multi_buffer_snapshot
 7273                .anchor_after(multi_buffer_snapshot.len())
 7274                .to_point(&multi_buffer_snapshot);
 7275            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7276            self.debounced_selection_highlight_task = Some((
 7277                query_range.clone(),
 7278                self.update_selection_occurrence_highlights(
 7279                    query_text,
 7280                    query_range,
 7281                    multi_buffer_full_range,
 7282                    true,
 7283                    window,
 7284                    cx,
 7285                ),
 7286            ));
 7287        }
 7288    }
 7289
 7290    pub fn refresh_edit_prediction(
 7291        &mut self,
 7292        debounce: bool,
 7293        user_requested: bool,
 7294        window: &mut Window,
 7295        cx: &mut Context<Self>,
 7296    ) -> Option<()> {
 7297        if DisableAiSettings::get_global(cx).disable_ai {
 7298            return None;
 7299        }
 7300
 7301        let provider = self.edit_prediction_provider()?;
 7302        let cursor = self.selections.newest_anchor().head();
 7303        let (buffer, cursor_buffer_position) =
 7304            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7305
 7306        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7307            self.discard_edit_prediction(false, cx);
 7308            return None;
 7309        }
 7310
 7311        self.update_visible_edit_prediction(window, cx);
 7312
 7313        if !user_requested
 7314            && (!self.should_show_edit_predictions()
 7315                || !self.is_focused(window)
 7316                || buffer.read(cx).is_empty())
 7317        {
 7318            self.discard_edit_prediction(false, cx);
 7319            return None;
 7320        }
 7321
 7322        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7323        Some(())
 7324    }
 7325
 7326    fn show_edit_predictions_in_menu(&self) -> bool {
 7327        match self.edit_prediction_settings {
 7328            EditPredictionSettings::Disabled => false,
 7329            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7330        }
 7331    }
 7332
 7333    pub fn edit_predictions_enabled(&self) -> bool {
 7334        match self.edit_prediction_settings {
 7335            EditPredictionSettings::Disabled => false,
 7336            EditPredictionSettings::Enabled { .. } => true,
 7337        }
 7338    }
 7339
 7340    fn edit_prediction_requires_modifier(&self) -> bool {
 7341        match self.edit_prediction_settings {
 7342            EditPredictionSettings::Disabled => false,
 7343            EditPredictionSettings::Enabled {
 7344                preview_requires_modifier,
 7345                ..
 7346            } => preview_requires_modifier,
 7347        }
 7348    }
 7349
 7350    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7351        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7352            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7353            self.discard_edit_prediction(false, cx);
 7354        } else {
 7355            let selection = self.selections.newest_anchor();
 7356            let cursor = selection.head();
 7357
 7358            if let Some((buffer, cursor_buffer_position)) =
 7359                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7360            {
 7361                self.edit_prediction_settings =
 7362                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7363            }
 7364        }
 7365    }
 7366
 7367    fn edit_prediction_settings_at_position(
 7368        &self,
 7369        buffer: &Entity<Buffer>,
 7370        buffer_position: language::Anchor,
 7371        cx: &App,
 7372    ) -> EditPredictionSettings {
 7373        if !self.mode.is_full()
 7374            || !self.show_edit_predictions_override.unwrap_or(true)
 7375            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7376        {
 7377            return EditPredictionSettings::Disabled;
 7378        }
 7379
 7380        let buffer = buffer.read(cx);
 7381
 7382        let file = buffer.file();
 7383
 7384        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7385            return EditPredictionSettings::Disabled;
 7386        };
 7387
 7388        let by_provider = matches!(
 7389            self.menu_edit_predictions_policy,
 7390            MenuEditPredictionsPolicy::ByProvider
 7391        );
 7392
 7393        let show_in_menu = by_provider
 7394            && self
 7395                .edit_prediction_provider
 7396                .as_ref()
 7397                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7398
 7399        let preview_requires_modifier =
 7400            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7401
 7402        EditPredictionSettings::Enabled {
 7403            show_in_menu,
 7404            preview_requires_modifier,
 7405        }
 7406    }
 7407
 7408    fn should_show_edit_predictions(&self) -> bool {
 7409        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7410    }
 7411
 7412    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7413        matches!(
 7414            self.edit_prediction_preview,
 7415            EditPredictionPreview::Active { .. }
 7416        )
 7417    }
 7418
 7419    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7420        let cursor = self.selections.newest_anchor().head();
 7421        if let Some((buffer, cursor_position)) =
 7422            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7423        {
 7424            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7425        } else {
 7426            false
 7427        }
 7428    }
 7429
 7430    pub fn supports_minimap(&self, cx: &App) -> bool {
 7431        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7432    }
 7433
 7434    fn edit_predictions_enabled_in_buffer(
 7435        &self,
 7436        buffer: &Entity<Buffer>,
 7437        buffer_position: language::Anchor,
 7438        cx: &App,
 7439    ) -> bool {
 7440        maybe!({
 7441            if self.read_only(cx) {
 7442                return Some(false);
 7443            }
 7444            let provider = self.edit_prediction_provider()?;
 7445            if !provider.is_enabled(buffer, buffer_position, cx) {
 7446                return Some(false);
 7447            }
 7448            let buffer = buffer.read(cx);
 7449            let Some(file) = buffer.file() else {
 7450                return Some(true);
 7451            };
 7452            let settings = all_language_settings(Some(file), cx);
 7453            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7454        })
 7455        .unwrap_or(false)
 7456    }
 7457
 7458    fn cycle_edit_prediction(
 7459        &mut self,
 7460        direction: Direction,
 7461        window: &mut Window,
 7462        cx: &mut Context<Self>,
 7463    ) -> Option<()> {
 7464        let provider = self.edit_prediction_provider()?;
 7465        let cursor = self.selections.newest_anchor().head();
 7466        let (buffer, cursor_buffer_position) =
 7467            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7468        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7469            return None;
 7470        }
 7471
 7472        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7473        self.update_visible_edit_prediction(window, cx);
 7474
 7475        Some(())
 7476    }
 7477
 7478    pub fn show_edit_prediction(
 7479        &mut self,
 7480        _: &ShowEditPrediction,
 7481        window: &mut Window,
 7482        cx: &mut Context<Self>,
 7483    ) {
 7484        if !self.has_active_edit_prediction() {
 7485            self.refresh_edit_prediction(false, true, window, cx);
 7486            return;
 7487        }
 7488
 7489        self.update_visible_edit_prediction(window, cx);
 7490    }
 7491
 7492    pub fn display_cursor_names(
 7493        &mut self,
 7494        _: &DisplayCursorNames,
 7495        window: &mut Window,
 7496        cx: &mut Context<Self>,
 7497    ) {
 7498        self.show_cursor_names(window, cx);
 7499    }
 7500
 7501    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7502        self.show_cursor_names = true;
 7503        cx.notify();
 7504        cx.spawn_in(window, async move |this, cx| {
 7505            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7506            this.update(cx, |this, cx| {
 7507                this.show_cursor_names = false;
 7508                cx.notify()
 7509            })
 7510            .ok()
 7511        })
 7512        .detach();
 7513    }
 7514
 7515    pub fn next_edit_prediction(
 7516        &mut self,
 7517        _: &NextEditPrediction,
 7518        window: &mut Window,
 7519        cx: &mut Context<Self>,
 7520    ) {
 7521        if self.has_active_edit_prediction() {
 7522            self.cycle_edit_prediction(Direction::Next, window, cx);
 7523        } else {
 7524            let is_copilot_disabled = self
 7525                .refresh_edit_prediction(false, true, window, cx)
 7526                .is_none();
 7527            if is_copilot_disabled {
 7528                cx.propagate();
 7529            }
 7530        }
 7531    }
 7532
 7533    pub fn previous_edit_prediction(
 7534        &mut self,
 7535        _: &PreviousEditPrediction,
 7536        window: &mut Window,
 7537        cx: &mut Context<Self>,
 7538    ) {
 7539        if self.has_active_edit_prediction() {
 7540            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7541        } else {
 7542            let is_copilot_disabled = self
 7543                .refresh_edit_prediction(false, true, window, cx)
 7544                .is_none();
 7545            if is_copilot_disabled {
 7546                cx.propagate();
 7547            }
 7548        }
 7549    }
 7550
 7551    pub fn accept_edit_prediction(
 7552        &mut self,
 7553        _: &AcceptEditPrediction,
 7554        window: &mut Window,
 7555        cx: &mut Context<Self>,
 7556    ) {
 7557        if self.show_edit_predictions_in_menu() {
 7558            self.hide_context_menu(window, cx);
 7559        }
 7560
 7561        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7562            return;
 7563        };
 7564
 7565        match &active_edit_prediction.completion {
 7566            EditPrediction::MoveWithin { target, .. } => {
 7567                let target = *target;
 7568
 7569                if let Some(position_map) = &self.last_position_map {
 7570                    if position_map
 7571                        .visible_row_range
 7572                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7573                        || !self.edit_prediction_requires_modifier()
 7574                    {
 7575                        self.unfold_ranges(&[target..target], true, false, cx);
 7576                        // Note that this is also done in vim's handler of the Tab action.
 7577                        self.change_selections(
 7578                            SelectionEffects::scroll(Autoscroll::newest()),
 7579                            window,
 7580                            cx,
 7581                            |selections| {
 7582                                selections.select_anchor_ranges([target..target]);
 7583                            },
 7584                        );
 7585                        self.clear_row_highlights::<EditPredictionPreview>();
 7586
 7587                        self.edit_prediction_preview
 7588                            .set_previous_scroll_position(None);
 7589                    } else {
 7590                        self.edit_prediction_preview
 7591                            .set_previous_scroll_position(Some(
 7592                                position_map.snapshot.scroll_anchor,
 7593                            ));
 7594
 7595                        self.highlight_rows::<EditPredictionPreview>(
 7596                            target..target,
 7597                            cx.theme().colors().editor_highlighted_line_background,
 7598                            RowHighlightOptions {
 7599                                autoscroll: true,
 7600                                ..Default::default()
 7601                            },
 7602                            cx,
 7603                        );
 7604                        self.request_autoscroll(Autoscroll::fit(), cx);
 7605                    }
 7606                }
 7607            }
 7608            EditPrediction::MoveOutside { snapshot, target } => {
 7609                if let Some(workspace) = self.workspace() {
 7610                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7611                        .detach_and_log_err(cx);
 7612                }
 7613            }
 7614            EditPrediction::Edit { edits, .. } => {
 7615                self.report_edit_prediction_event(
 7616                    active_edit_prediction.completion_id.clone(),
 7617                    true,
 7618                    cx,
 7619                );
 7620
 7621                if let Some(provider) = self.edit_prediction_provider() {
 7622                    provider.accept(cx);
 7623                }
 7624
 7625                // Store the transaction ID and selections before applying the edit
 7626                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7627
 7628                let snapshot = self.buffer.read(cx).snapshot(cx);
 7629                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7630
 7631                self.buffer.update(cx, |buffer, cx| {
 7632                    buffer.edit(edits.iter().cloned(), None, cx)
 7633                });
 7634
 7635                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7636                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7637                });
 7638
 7639                let selections = self.selections.disjoint_anchors_arc();
 7640                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7641                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7642                    if has_new_transaction {
 7643                        self.selection_history
 7644                            .insert_transaction(transaction_id_now, selections);
 7645                    }
 7646                }
 7647
 7648                self.update_visible_edit_prediction(window, cx);
 7649                if self.active_edit_prediction.is_none() {
 7650                    self.refresh_edit_prediction(true, true, window, cx);
 7651                }
 7652
 7653                cx.notify();
 7654            }
 7655        }
 7656
 7657        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7658    }
 7659
 7660    pub fn accept_partial_edit_prediction(
 7661        &mut self,
 7662        _: &AcceptPartialEditPrediction,
 7663        window: &mut Window,
 7664        cx: &mut Context<Self>,
 7665    ) {
 7666        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7667            return;
 7668        };
 7669        if self.selections.count() != 1 {
 7670            return;
 7671        }
 7672
 7673        match &active_edit_prediction.completion {
 7674            EditPrediction::MoveWithin { target, .. } => {
 7675                let target = *target;
 7676                self.change_selections(
 7677                    SelectionEffects::scroll(Autoscroll::newest()),
 7678                    window,
 7679                    cx,
 7680                    |selections| {
 7681                        selections.select_anchor_ranges([target..target]);
 7682                    },
 7683                );
 7684            }
 7685            EditPrediction::MoveOutside { snapshot, target } => {
 7686                if let Some(workspace) = self.workspace() {
 7687                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7688                        .detach_and_log_err(cx);
 7689                }
 7690            }
 7691            EditPrediction::Edit { edits, .. } => {
 7692                self.report_edit_prediction_event(
 7693                    active_edit_prediction.completion_id.clone(),
 7694                    true,
 7695                    cx,
 7696                );
 7697
 7698                // Find an insertion that starts at the cursor position.
 7699                let snapshot = self.buffer.read(cx).snapshot(cx);
 7700                let cursor_offset = self
 7701                    .selections
 7702                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7703                    .head();
 7704                let insertion = edits.iter().find_map(|(range, text)| {
 7705                    let range = range.to_offset(&snapshot);
 7706                    if range.is_empty() && range.start == cursor_offset {
 7707                        Some(text)
 7708                    } else {
 7709                        None
 7710                    }
 7711                });
 7712
 7713                if let Some(text) = insertion {
 7714                    let mut partial_completion = text
 7715                        .chars()
 7716                        .by_ref()
 7717                        .take_while(|c| c.is_alphabetic())
 7718                        .collect::<String>();
 7719                    if partial_completion.is_empty() {
 7720                        partial_completion = text
 7721                            .chars()
 7722                            .by_ref()
 7723                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7724                            .collect::<String>();
 7725                    }
 7726
 7727                    cx.emit(EditorEvent::InputHandled {
 7728                        utf16_range_to_replace: None,
 7729                        text: partial_completion.clone().into(),
 7730                    });
 7731
 7732                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7733
 7734                    self.refresh_edit_prediction(true, true, window, cx);
 7735                    cx.notify();
 7736                } else {
 7737                    self.accept_edit_prediction(&Default::default(), window, cx);
 7738                }
 7739            }
 7740        }
 7741    }
 7742
 7743    fn discard_edit_prediction(
 7744        &mut self,
 7745        should_report_edit_prediction_event: bool,
 7746        cx: &mut Context<Self>,
 7747    ) -> bool {
 7748        if should_report_edit_prediction_event {
 7749            let completion_id = self
 7750                .active_edit_prediction
 7751                .as_ref()
 7752                .and_then(|active_completion| active_completion.completion_id.clone());
 7753
 7754            self.report_edit_prediction_event(completion_id, false, cx);
 7755        }
 7756
 7757        if let Some(provider) = self.edit_prediction_provider() {
 7758            provider.discard(cx);
 7759        }
 7760
 7761        self.take_active_edit_prediction(cx)
 7762    }
 7763
 7764    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7765        let Some(provider) = self.edit_prediction_provider() else {
 7766            return;
 7767        };
 7768
 7769        let Some((_, buffer, _)) = self
 7770            .buffer
 7771            .read(cx)
 7772            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7773        else {
 7774            return;
 7775        };
 7776
 7777        let extension = buffer
 7778            .read(cx)
 7779            .file()
 7780            .and_then(|file| Some(file.path().extension()?.to_string()));
 7781
 7782        let event_type = match accepted {
 7783            true => "Edit Prediction Accepted",
 7784            false => "Edit Prediction Discarded",
 7785        };
 7786        telemetry::event!(
 7787            event_type,
 7788            provider = provider.name(),
 7789            prediction_id = id,
 7790            suggestion_accepted = accepted,
 7791            file_extension = extension,
 7792        );
 7793    }
 7794
 7795    fn open_editor_at_anchor(
 7796        snapshot: &language::BufferSnapshot,
 7797        target: language::Anchor,
 7798        workspace: &Entity<Workspace>,
 7799        window: &mut Window,
 7800        cx: &mut App,
 7801    ) -> Task<Result<()>> {
 7802        workspace.update(cx, |workspace, cx| {
 7803            let path = snapshot.file().map(|file| file.full_path(cx));
 7804            let Some(path) =
 7805                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7806            else {
 7807                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7808            };
 7809            let target = text::ToPoint::to_point(&target, snapshot);
 7810            let item = workspace.open_path(path, None, true, window, cx);
 7811            window.spawn(cx, async move |cx| {
 7812                let Some(editor) = item.await?.downcast::<Editor>() else {
 7813                    return Ok(());
 7814                };
 7815                editor
 7816                    .update_in(cx, |editor, window, cx| {
 7817                        editor.go_to_singleton_buffer_point(target, window, cx);
 7818                    })
 7819                    .ok();
 7820                anyhow::Ok(())
 7821            })
 7822        })
 7823    }
 7824
 7825    pub fn has_active_edit_prediction(&self) -> bool {
 7826        self.active_edit_prediction.is_some()
 7827    }
 7828
 7829    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7830        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7831            return false;
 7832        };
 7833
 7834        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7835        self.clear_highlights::<EditPredictionHighlight>(cx);
 7836        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7837        true
 7838    }
 7839
 7840    /// Returns true when we're displaying the edit prediction popover below the cursor
 7841    /// like we are not previewing and the LSP autocomplete menu is visible
 7842    /// or we are in `when_holding_modifier` mode.
 7843    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7844        if self.edit_prediction_preview_is_active()
 7845            || !self.show_edit_predictions_in_menu()
 7846            || !self.edit_predictions_enabled()
 7847        {
 7848            return false;
 7849        }
 7850
 7851        if self.has_visible_completions_menu() {
 7852            return true;
 7853        }
 7854
 7855        has_completion && self.edit_prediction_requires_modifier()
 7856    }
 7857
 7858    fn handle_modifiers_changed(
 7859        &mut self,
 7860        modifiers: Modifiers,
 7861        position_map: &PositionMap,
 7862        window: &mut Window,
 7863        cx: &mut Context<Self>,
 7864    ) {
 7865        // Ensure that the edit prediction preview is updated, even when not
 7866        // enabled, if there's an active edit prediction preview.
 7867        if self.show_edit_predictions_in_menu()
 7868            || matches!(
 7869                self.edit_prediction_preview,
 7870                EditPredictionPreview::Active { .. }
 7871            )
 7872        {
 7873            self.update_edit_prediction_preview(&modifiers, window, cx);
 7874        }
 7875
 7876        self.update_selection_mode(&modifiers, position_map, window, cx);
 7877
 7878        let mouse_position = window.mouse_position();
 7879        if !position_map.text_hitbox.is_hovered(window) {
 7880            return;
 7881        }
 7882
 7883        self.update_hovered_link(
 7884            position_map.point_for_position(mouse_position),
 7885            &position_map.snapshot,
 7886            modifiers,
 7887            window,
 7888            cx,
 7889        )
 7890    }
 7891
 7892    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7893        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7894            MultiCursorModifier::Alt => modifiers.secondary(),
 7895            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7896        }
 7897    }
 7898
 7899    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7900        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7901            MultiCursorModifier::Alt => modifiers.alt,
 7902            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7903        }
 7904    }
 7905
 7906    fn columnar_selection_mode(
 7907        modifiers: &Modifiers,
 7908        cx: &mut Context<Self>,
 7909    ) -> Option<ColumnarMode> {
 7910        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7911            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7912                Some(ColumnarMode::FromMouse)
 7913            } else if Self::is_alt_pressed(modifiers, cx) {
 7914                Some(ColumnarMode::FromSelection)
 7915            } else {
 7916                None
 7917            }
 7918        } else {
 7919            None
 7920        }
 7921    }
 7922
 7923    fn update_selection_mode(
 7924        &mut self,
 7925        modifiers: &Modifiers,
 7926        position_map: &PositionMap,
 7927        window: &mut Window,
 7928        cx: &mut Context<Self>,
 7929    ) {
 7930        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7931            return;
 7932        };
 7933        if self.selections.pending_anchor().is_none() {
 7934            return;
 7935        }
 7936
 7937        let mouse_position = window.mouse_position();
 7938        let point_for_position = position_map.point_for_position(mouse_position);
 7939        let position = point_for_position.previous_valid;
 7940
 7941        self.select(
 7942            SelectPhase::BeginColumnar {
 7943                position,
 7944                reset: false,
 7945                mode,
 7946                goal_column: point_for_position.exact_unclipped.column(),
 7947            },
 7948            window,
 7949            cx,
 7950        );
 7951    }
 7952
 7953    fn update_edit_prediction_preview(
 7954        &mut self,
 7955        modifiers: &Modifiers,
 7956        window: &mut Window,
 7957        cx: &mut Context<Self>,
 7958    ) {
 7959        let mut modifiers_held = false;
 7960        if let Some(accept_keystroke) = self
 7961            .accept_edit_prediction_keybind(false, window, cx)
 7962            .keystroke()
 7963        {
 7964            modifiers_held = modifiers_held
 7965                || (accept_keystroke.modifiers() == modifiers
 7966                    && accept_keystroke.modifiers().modified());
 7967        };
 7968        if let Some(accept_partial_keystroke) = self
 7969            .accept_edit_prediction_keybind(true, window, cx)
 7970            .keystroke()
 7971        {
 7972            modifiers_held = modifiers_held
 7973                || (accept_partial_keystroke.modifiers() == modifiers
 7974                    && accept_partial_keystroke.modifiers().modified());
 7975        }
 7976
 7977        if modifiers_held {
 7978            if matches!(
 7979                self.edit_prediction_preview,
 7980                EditPredictionPreview::Inactive { .. }
 7981            ) {
 7982                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7983                    provider.provider.did_show(cx)
 7984                }
 7985
 7986                self.edit_prediction_preview = EditPredictionPreview::Active {
 7987                    previous_scroll_position: None,
 7988                    since: Instant::now(),
 7989                };
 7990
 7991                self.update_visible_edit_prediction(window, cx);
 7992                cx.notify();
 7993            }
 7994        } else if let EditPredictionPreview::Active {
 7995            previous_scroll_position,
 7996            since,
 7997        } = self.edit_prediction_preview
 7998        {
 7999            if let (Some(previous_scroll_position), Some(position_map)) =
 8000                (previous_scroll_position, self.last_position_map.as_ref())
 8001            {
 8002                self.set_scroll_position(
 8003                    previous_scroll_position
 8004                        .scroll_position(&position_map.snapshot.display_snapshot),
 8005                    window,
 8006                    cx,
 8007                );
 8008            }
 8009
 8010            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8011                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8012            };
 8013            self.clear_row_highlights::<EditPredictionPreview>();
 8014            self.update_visible_edit_prediction(window, cx);
 8015            cx.notify();
 8016        }
 8017    }
 8018
 8019    fn update_visible_edit_prediction(
 8020        &mut self,
 8021        _window: &mut Window,
 8022        cx: &mut Context<Self>,
 8023    ) -> Option<()> {
 8024        if DisableAiSettings::get_global(cx).disable_ai {
 8025            return None;
 8026        }
 8027
 8028        if self.ime_transaction.is_some() {
 8029            self.discard_edit_prediction(false, cx);
 8030            return None;
 8031        }
 8032
 8033        let selection = self.selections.newest_anchor();
 8034        let cursor = selection.head();
 8035        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8036        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8037        let excerpt_id = cursor.excerpt_id;
 8038
 8039        let show_in_menu = self.show_edit_predictions_in_menu();
 8040        let completions_menu_has_precedence = !show_in_menu
 8041            && (self.context_menu.borrow().is_some()
 8042                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8043
 8044        if completions_menu_has_precedence
 8045            || !offset_selection.is_empty()
 8046            || self
 8047                .active_edit_prediction
 8048                .as_ref()
 8049                .is_some_and(|completion| {
 8050                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8051                        return false;
 8052                    };
 8053                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8054                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8055                    !invalidation_range.contains(&offset_selection.head())
 8056                })
 8057        {
 8058            self.discard_edit_prediction(false, cx);
 8059            return None;
 8060        }
 8061
 8062        self.take_active_edit_prediction(cx);
 8063        let Some(provider) = self.edit_prediction_provider() else {
 8064            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8065            return None;
 8066        };
 8067
 8068        let (buffer, cursor_buffer_position) =
 8069            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8070
 8071        self.edit_prediction_settings =
 8072            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8073
 8074        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8075
 8076        if self.edit_prediction_indent_conflict {
 8077            let cursor_point = cursor.to_point(&multibuffer);
 8078            let mut suggested_indent = None;
 8079            multibuffer.suggested_indents_callback(
 8080                cursor_point.row..cursor_point.row + 1,
 8081                |_, indent| {
 8082                    suggested_indent = Some(indent);
 8083                    ControlFlow::Break(())
 8084                },
 8085                cx,
 8086            );
 8087
 8088            if let Some(indent) = suggested_indent
 8089                && indent.len == cursor_point.column
 8090            {
 8091                self.edit_prediction_indent_conflict = false;
 8092            }
 8093        }
 8094
 8095        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8096
 8097        let (completion_id, edits, edit_preview) = match edit_prediction {
 8098            edit_prediction::EditPrediction::Local {
 8099                id,
 8100                edits,
 8101                edit_preview,
 8102            } => (id, edits, edit_preview),
 8103            edit_prediction::EditPrediction::Jump {
 8104                id,
 8105                snapshot,
 8106                target,
 8107            } => {
 8108                self.stale_edit_prediction_in_menu = None;
 8109                self.active_edit_prediction = Some(EditPredictionState {
 8110                    inlay_ids: vec![],
 8111                    completion: EditPrediction::MoveOutside { snapshot, target },
 8112                    completion_id: id,
 8113                    invalidation_range: None,
 8114                });
 8115                cx.notify();
 8116                return Some(());
 8117            }
 8118        };
 8119
 8120        let edits = edits
 8121            .into_iter()
 8122            .flat_map(|(range, new_text)| {
 8123                Some((
 8124                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8125                    new_text,
 8126                ))
 8127            })
 8128            .collect::<Vec<_>>();
 8129        if edits.is_empty() {
 8130            return None;
 8131        }
 8132
 8133        let first_edit_start = edits.first().unwrap().0.start;
 8134        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8135        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8136
 8137        let last_edit_end = edits.last().unwrap().0.end;
 8138        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8139        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8140
 8141        let cursor_row = cursor.to_point(&multibuffer).row;
 8142
 8143        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8144
 8145        let mut inlay_ids = Vec::new();
 8146        let invalidation_row_range;
 8147        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8148            Some(cursor_row..edit_end_row)
 8149        } else if cursor_row > edit_end_row {
 8150            Some(edit_start_row..cursor_row)
 8151        } else {
 8152            None
 8153        };
 8154        let supports_jump = self
 8155            .edit_prediction_provider
 8156            .as_ref()
 8157            .map(|provider| provider.provider.supports_jump_to_edit())
 8158            .unwrap_or(true);
 8159
 8160        let is_move = supports_jump
 8161            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8162        let completion = if is_move {
 8163            invalidation_row_range =
 8164                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8165            let target = first_edit_start;
 8166            EditPrediction::MoveWithin { target, snapshot }
 8167        } else {
 8168            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8169                && !self.edit_predictions_hidden_for_vim_mode;
 8170
 8171            if show_completions_in_buffer {
 8172                if let Some(provider) = &self.edit_prediction_provider {
 8173                    provider.provider.did_show(cx);
 8174                }
 8175                if edits
 8176                    .iter()
 8177                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8178                {
 8179                    let mut inlays = Vec::new();
 8180                    for (range, new_text) in &edits {
 8181                        let inlay = Inlay::edit_prediction(
 8182                            post_inc(&mut self.next_inlay_id),
 8183                            range.start,
 8184                            new_text.as_ref(),
 8185                        );
 8186                        inlay_ids.push(inlay.id);
 8187                        inlays.push(inlay);
 8188                    }
 8189
 8190                    self.splice_inlays(&[], inlays, cx);
 8191                } else {
 8192                    let background_color = cx.theme().status().deleted_background;
 8193                    self.highlight_text::<EditPredictionHighlight>(
 8194                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8195                        HighlightStyle {
 8196                            background_color: Some(background_color),
 8197                            ..Default::default()
 8198                        },
 8199                        cx,
 8200                    );
 8201                }
 8202            }
 8203
 8204            invalidation_row_range = edit_start_row..edit_end_row;
 8205
 8206            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8207                if provider.show_tab_accept_marker() {
 8208                    EditDisplayMode::TabAccept
 8209                } else {
 8210                    EditDisplayMode::Inline
 8211                }
 8212            } else {
 8213                EditDisplayMode::DiffPopover
 8214            };
 8215
 8216            EditPrediction::Edit {
 8217                edits,
 8218                edit_preview,
 8219                display_mode,
 8220                snapshot,
 8221            }
 8222        };
 8223
 8224        let invalidation_range = multibuffer
 8225            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8226            ..multibuffer.anchor_after(Point::new(
 8227                invalidation_row_range.end,
 8228                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8229            ));
 8230
 8231        self.stale_edit_prediction_in_menu = None;
 8232        self.active_edit_prediction = Some(EditPredictionState {
 8233            inlay_ids,
 8234            completion,
 8235            completion_id,
 8236            invalidation_range: Some(invalidation_range),
 8237        });
 8238
 8239        cx.notify();
 8240
 8241        Some(())
 8242    }
 8243
 8244    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8245        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8246    }
 8247
 8248    fn clear_tasks(&mut self) {
 8249        self.tasks.clear()
 8250    }
 8251
 8252    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8253        if self.tasks.insert(key, value).is_some() {
 8254            // This case should hopefully be rare, but just in case...
 8255            log::error!(
 8256                "multiple different run targets found on a single line, only the last target will be rendered"
 8257            )
 8258        }
 8259    }
 8260
 8261    /// Get all display points of breakpoints that will be rendered within editor
 8262    ///
 8263    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8264    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8265    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8266    fn active_breakpoints(
 8267        &self,
 8268        range: Range<DisplayRow>,
 8269        window: &mut Window,
 8270        cx: &mut Context<Self>,
 8271    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8272        let mut breakpoint_display_points = HashMap::default();
 8273
 8274        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8275            return breakpoint_display_points;
 8276        };
 8277
 8278        let snapshot = self.snapshot(window, cx);
 8279
 8280        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8281        let Some(project) = self.project() else {
 8282            return breakpoint_display_points;
 8283        };
 8284
 8285        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8286            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8287
 8288        for (buffer_snapshot, range, excerpt_id) in
 8289            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8290        {
 8291            let Some(buffer) = project
 8292                .read(cx)
 8293                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8294            else {
 8295                continue;
 8296            };
 8297            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8298                &buffer,
 8299                Some(
 8300                    buffer_snapshot.anchor_before(range.start)
 8301                        ..buffer_snapshot.anchor_after(range.end),
 8302                ),
 8303                buffer_snapshot,
 8304                cx,
 8305            );
 8306            for (breakpoint, state) in breakpoints {
 8307                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8308                let position = multi_buffer_anchor
 8309                    .to_point(&multi_buffer_snapshot)
 8310                    .to_display_point(&snapshot);
 8311
 8312                breakpoint_display_points.insert(
 8313                    position.row(),
 8314                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8315                );
 8316            }
 8317        }
 8318
 8319        breakpoint_display_points
 8320    }
 8321
 8322    fn breakpoint_context_menu(
 8323        &self,
 8324        anchor: Anchor,
 8325        window: &mut Window,
 8326        cx: &mut Context<Self>,
 8327    ) -> Entity<ui::ContextMenu> {
 8328        let weak_editor = cx.weak_entity();
 8329        let focus_handle = self.focus_handle(cx);
 8330
 8331        let row = self
 8332            .buffer
 8333            .read(cx)
 8334            .snapshot(cx)
 8335            .summary_for_anchor::<Point>(&anchor)
 8336            .row;
 8337
 8338        let breakpoint = self
 8339            .breakpoint_at_row(row, window, cx)
 8340            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8341
 8342        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8343            "Edit Log Breakpoint"
 8344        } else {
 8345            "Set Log Breakpoint"
 8346        };
 8347
 8348        let condition_breakpoint_msg = if breakpoint
 8349            .as_ref()
 8350            .is_some_and(|bp| bp.1.condition.is_some())
 8351        {
 8352            "Edit Condition Breakpoint"
 8353        } else {
 8354            "Set Condition Breakpoint"
 8355        };
 8356
 8357        let hit_condition_breakpoint_msg = if breakpoint
 8358            .as_ref()
 8359            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8360        {
 8361            "Edit Hit Condition Breakpoint"
 8362        } else {
 8363            "Set Hit Condition Breakpoint"
 8364        };
 8365
 8366        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8367            "Unset Breakpoint"
 8368        } else {
 8369            "Set Breakpoint"
 8370        };
 8371
 8372        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8373
 8374        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8375            BreakpointState::Enabled => Some("Disable"),
 8376            BreakpointState::Disabled => Some("Enable"),
 8377        });
 8378
 8379        let (anchor, breakpoint) =
 8380            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8381
 8382        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8383            menu.on_blur_subscription(Subscription::new(|| {}))
 8384                .context(focus_handle)
 8385                .when(run_to_cursor, |this| {
 8386                    let weak_editor = weak_editor.clone();
 8387                    this.entry("Run to cursor", None, move |window, cx| {
 8388                        weak_editor
 8389                            .update(cx, |editor, cx| {
 8390                                editor.change_selections(
 8391                                    SelectionEffects::no_scroll(),
 8392                                    window,
 8393                                    cx,
 8394                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8395                                );
 8396                            })
 8397                            .ok();
 8398
 8399                        window.dispatch_action(Box::new(RunToCursor), cx);
 8400                    })
 8401                    .separator()
 8402                })
 8403                .when_some(toggle_state_msg, |this, msg| {
 8404                    this.entry(msg, None, {
 8405                        let weak_editor = weak_editor.clone();
 8406                        let breakpoint = breakpoint.clone();
 8407                        move |_window, cx| {
 8408                            weak_editor
 8409                                .update(cx, |this, cx| {
 8410                                    this.edit_breakpoint_at_anchor(
 8411                                        anchor,
 8412                                        breakpoint.as_ref().clone(),
 8413                                        BreakpointEditAction::InvertState,
 8414                                        cx,
 8415                                    );
 8416                                })
 8417                                .log_err();
 8418                        }
 8419                    })
 8420                })
 8421                .entry(set_breakpoint_msg, None, {
 8422                    let weak_editor = weak_editor.clone();
 8423                    let breakpoint = breakpoint.clone();
 8424                    move |_window, cx| {
 8425                        weak_editor
 8426                            .update(cx, |this, cx| {
 8427                                this.edit_breakpoint_at_anchor(
 8428                                    anchor,
 8429                                    breakpoint.as_ref().clone(),
 8430                                    BreakpointEditAction::Toggle,
 8431                                    cx,
 8432                                );
 8433                            })
 8434                            .log_err();
 8435                    }
 8436                })
 8437                .entry(log_breakpoint_msg, None, {
 8438                    let breakpoint = breakpoint.clone();
 8439                    let weak_editor = weak_editor.clone();
 8440                    move |window, cx| {
 8441                        weak_editor
 8442                            .update(cx, |this, cx| {
 8443                                this.add_edit_breakpoint_block(
 8444                                    anchor,
 8445                                    breakpoint.as_ref(),
 8446                                    BreakpointPromptEditAction::Log,
 8447                                    window,
 8448                                    cx,
 8449                                );
 8450                            })
 8451                            .log_err();
 8452                    }
 8453                })
 8454                .entry(condition_breakpoint_msg, None, {
 8455                    let breakpoint = breakpoint.clone();
 8456                    let weak_editor = weak_editor.clone();
 8457                    move |window, cx| {
 8458                        weak_editor
 8459                            .update(cx, |this, cx| {
 8460                                this.add_edit_breakpoint_block(
 8461                                    anchor,
 8462                                    breakpoint.as_ref(),
 8463                                    BreakpointPromptEditAction::Condition,
 8464                                    window,
 8465                                    cx,
 8466                                );
 8467                            })
 8468                            .log_err();
 8469                    }
 8470                })
 8471                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8472                    weak_editor
 8473                        .update(cx, |this, cx| {
 8474                            this.add_edit_breakpoint_block(
 8475                                anchor,
 8476                                breakpoint.as_ref(),
 8477                                BreakpointPromptEditAction::HitCondition,
 8478                                window,
 8479                                cx,
 8480                            );
 8481                        })
 8482                        .log_err();
 8483                })
 8484        })
 8485    }
 8486
 8487    fn render_breakpoint(
 8488        &self,
 8489        position: Anchor,
 8490        row: DisplayRow,
 8491        breakpoint: &Breakpoint,
 8492        state: Option<BreakpointSessionState>,
 8493        cx: &mut Context<Self>,
 8494    ) -> IconButton {
 8495        let is_rejected = state.is_some_and(|s| !s.verified);
 8496        // Is it a breakpoint that shows up when hovering over gutter?
 8497        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8498            (false, false),
 8499            |PhantomBreakpointIndicator {
 8500                 is_active,
 8501                 display_row,
 8502                 collides_with_existing_breakpoint,
 8503             }| {
 8504                (
 8505                    is_active && display_row == row,
 8506                    collides_with_existing_breakpoint,
 8507                )
 8508            },
 8509        );
 8510
 8511        let (color, icon) = {
 8512            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8513                (false, false) => ui::IconName::DebugBreakpoint,
 8514                (true, false) => ui::IconName::DebugLogBreakpoint,
 8515                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8516                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8517            };
 8518
 8519            let color = cx.theme().colors();
 8520
 8521            let color = if is_phantom {
 8522                if collides_with_existing {
 8523                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8524                } else {
 8525                    Color::Hint
 8526                }
 8527            } else if is_rejected {
 8528                Color::Disabled
 8529            } else {
 8530                Color::Debugger
 8531            };
 8532
 8533            (color, icon)
 8534        };
 8535
 8536        let breakpoint = Arc::from(breakpoint.clone());
 8537
 8538        let alt_as_text = gpui::Keystroke {
 8539            modifiers: Modifiers::secondary_key(),
 8540            ..Default::default()
 8541        };
 8542        let primary_action_text = if breakpoint.is_disabled() {
 8543            "Enable breakpoint"
 8544        } else if is_phantom && !collides_with_existing {
 8545            "Set breakpoint"
 8546        } else {
 8547            "Unset breakpoint"
 8548        };
 8549        let focus_handle = self.focus_handle.clone();
 8550
 8551        let meta = if is_rejected {
 8552            SharedString::from("No executable code is associated with this line.")
 8553        } else if collides_with_existing && !breakpoint.is_disabled() {
 8554            SharedString::from(format!(
 8555                "{alt_as_text}-click to disable,\nright-click for more options."
 8556            ))
 8557        } else {
 8558            SharedString::from("Right-click for more options.")
 8559        };
 8560        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8561            .icon_size(IconSize::XSmall)
 8562            .size(ui::ButtonSize::None)
 8563            .when(is_rejected, |this| {
 8564                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8565            })
 8566            .icon_color(color)
 8567            .style(ButtonStyle::Transparent)
 8568            .on_click(cx.listener({
 8569                move |editor, event: &ClickEvent, window, cx| {
 8570                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8571                        BreakpointEditAction::InvertState
 8572                    } else {
 8573                        BreakpointEditAction::Toggle
 8574                    };
 8575
 8576                    window.focus(&editor.focus_handle(cx));
 8577                    editor.edit_breakpoint_at_anchor(
 8578                        position,
 8579                        breakpoint.as_ref().clone(),
 8580                        edit_action,
 8581                        cx,
 8582                    );
 8583                }
 8584            }))
 8585            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8586                editor.set_breakpoint_context_menu(
 8587                    row,
 8588                    Some(position),
 8589                    event.position(),
 8590                    window,
 8591                    cx,
 8592                );
 8593            }))
 8594            .tooltip(move |_window, cx| {
 8595                Tooltip::with_meta_in(
 8596                    primary_action_text,
 8597                    Some(&ToggleBreakpoint),
 8598                    meta.clone(),
 8599                    &focus_handle,
 8600                    cx,
 8601                )
 8602            })
 8603    }
 8604
 8605    fn build_tasks_context(
 8606        project: &Entity<Project>,
 8607        buffer: &Entity<Buffer>,
 8608        buffer_row: u32,
 8609        tasks: &Arc<RunnableTasks>,
 8610        cx: &mut Context<Self>,
 8611    ) -> Task<Option<task::TaskContext>> {
 8612        let position = Point::new(buffer_row, tasks.column);
 8613        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8614        let location = Location {
 8615            buffer: buffer.clone(),
 8616            range: range_start..range_start,
 8617        };
 8618        // Fill in the environmental variables from the tree-sitter captures
 8619        let mut captured_task_variables = TaskVariables::default();
 8620        for (capture_name, value) in tasks.extra_variables.clone() {
 8621            captured_task_variables.insert(
 8622                task::VariableName::Custom(capture_name.into()),
 8623                value.clone(),
 8624            );
 8625        }
 8626        project.update(cx, |project, cx| {
 8627            project.task_store().update(cx, |task_store, cx| {
 8628                task_store.task_context_for_location(captured_task_variables, location, cx)
 8629            })
 8630        })
 8631    }
 8632
 8633    pub fn spawn_nearest_task(
 8634        &mut self,
 8635        action: &SpawnNearestTask,
 8636        window: &mut Window,
 8637        cx: &mut Context<Self>,
 8638    ) {
 8639        let Some((workspace, _)) = self.workspace.clone() else {
 8640            return;
 8641        };
 8642        let Some(project) = self.project.clone() else {
 8643            return;
 8644        };
 8645
 8646        // Try to find a closest, enclosing node using tree-sitter that has a task
 8647        let Some((buffer, buffer_row, tasks)) = self
 8648            .find_enclosing_node_task(cx)
 8649            // Or find the task that's closest in row-distance.
 8650            .or_else(|| self.find_closest_task(cx))
 8651        else {
 8652            return;
 8653        };
 8654
 8655        let reveal_strategy = action.reveal;
 8656        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8657        cx.spawn_in(window, async move |_, cx| {
 8658            let context = task_context.await?;
 8659            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8660
 8661            let resolved = &mut resolved_task.resolved;
 8662            resolved.reveal = reveal_strategy;
 8663
 8664            workspace
 8665                .update_in(cx, |workspace, window, cx| {
 8666                    workspace.schedule_resolved_task(
 8667                        task_source_kind,
 8668                        resolved_task,
 8669                        false,
 8670                        window,
 8671                        cx,
 8672                    );
 8673                })
 8674                .ok()
 8675        })
 8676        .detach();
 8677    }
 8678
 8679    fn find_closest_task(
 8680        &mut self,
 8681        cx: &mut Context<Self>,
 8682    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8683        let cursor_row = self
 8684            .selections
 8685            .newest_adjusted(&self.display_snapshot(cx))
 8686            .head()
 8687            .row;
 8688
 8689        let ((buffer_id, row), tasks) = self
 8690            .tasks
 8691            .iter()
 8692            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8693
 8694        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8695        let tasks = Arc::new(tasks.to_owned());
 8696        Some((buffer, *row, tasks))
 8697    }
 8698
 8699    fn find_enclosing_node_task(
 8700        &mut self,
 8701        cx: &mut Context<Self>,
 8702    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8703        let snapshot = self.buffer.read(cx).snapshot(cx);
 8704        let offset = self
 8705            .selections
 8706            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8707            .head();
 8708        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8709        let offset = excerpt.map_offset_to_buffer(offset);
 8710        let buffer_id = excerpt.buffer().remote_id();
 8711
 8712        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8713        let mut cursor = layer.node().walk();
 8714
 8715        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8716            if cursor.node().end_byte() == offset.0 {
 8717                cursor.goto_next_sibling();
 8718            }
 8719        }
 8720
 8721        // Ascend to the smallest ancestor that contains the range and has a task.
 8722        loop {
 8723            let node = cursor.node();
 8724            let node_range = node.byte_range();
 8725            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8726
 8727            // Check if this node contains our offset
 8728            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8729                // If it contains offset, check for task
 8730                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8731                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8732                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8733                }
 8734            }
 8735
 8736            if !cursor.goto_parent() {
 8737                break;
 8738            }
 8739        }
 8740        None
 8741    }
 8742
 8743    fn render_run_indicator(
 8744        &self,
 8745        _style: &EditorStyle,
 8746        is_active: bool,
 8747        row: DisplayRow,
 8748        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8749        cx: &mut Context<Self>,
 8750    ) -> IconButton {
 8751        let color = Color::Muted;
 8752        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8753
 8754        IconButton::new(
 8755            ("run_indicator", row.0 as usize),
 8756            ui::IconName::PlayOutlined,
 8757        )
 8758        .shape(ui::IconButtonShape::Square)
 8759        .icon_size(IconSize::XSmall)
 8760        .icon_color(color)
 8761        .toggle_state(is_active)
 8762        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8763            let quick_launch = match e {
 8764                ClickEvent::Keyboard(_) => true,
 8765                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8766            };
 8767
 8768            window.focus(&editor.focus_handle(cx));
 8769            editor.toggle_code_actions(
 8770                &ToggleCodeActions {
 8771                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8772                    quick_launch,
 8773                },
 8774                window,
 8775                cx,
 8776            );
 8777        }))
 8778        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8779            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8780        }))
 8781    }
 8782
 8783    pub fn context_menu_visible(&self) -> bool {
 8784        !self.edit_prediction_preview_is_active()
 8785            && self
 8786                .context_menu
 8787                .borrow()
 8788                .as_ref()
 8789                .is_some_and(|menu| menu.visible())
 8790    }
 8791
 8792    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8793        self.context_menu
 8794            .borrow()
 8795            .as_ref()
 8796            .map(|menu| menu.origin())
 8797    }
 8798
 8799    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8800        self.context_menu_options = Some(options);
 8801    }
 8802
 8803    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8804    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8805
 8806    fn render_edit_prediction_popover(
 8807        &mut self,
 8808        text_bounds: &Bounds<Pixels>,
 8809        content_origin: gpui::Point<Pixels>,
 8810        right_margin: Pixels,
 8811        editor_snapshot: &EditorSnapshot,
 8812        visible_row_range: Range<DisplayRow>,
 8813        scroll_top: ScrollOffset,
 8814        scroll_bottom: ScrollOffset,
 8815        line_layouts: &[LineWithInvisibles],
 8816        line_height: Pixels,
 8817        scroll_position: gpui::Point<ScrollOffset>,
 8818        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8819        newest_selection_head: Option<DisplayPoint>,
 8820        editor_width: Pixels,
 8821        style: &EditorStyle,
 8822        window: &mut Window,
 8823        cx: &mut App,
 8824    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8825        if self.mode().is_minimap() {
 8826            return None;
 8827        }
 8828        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8829
 8830        if self.edit_prediction_visible_in_cursor_popover(true) {
 8831            return None;
 8832        }
 8833
 8834        match &active_edit_prediction.completion {
 8835            EditPrediction::MoveWithin { target, .. } => {
 8836                let target_display_point = target.to_display_point(editor_snapshot);
 8837
 8838                if self.edit_prediction_requires_modifier() {
 8839                    if !self.edit_prediction_preview_is_active() {
 8840                        return None;
 8841                    }
 8842
 8843                    self.render_edit_prediction_modifier_jump_popover(
 8844                        text_bounds,
 8845                        content_origin,
 8846                        visible_row_range,
 8847                        line_layouts,
 8848                        line_height,
 8849                        scroll_pixel_position,
 8850                        newest_selection_head,
 8851                        target_display_point,
 8852                        window,
 8853                        cx,
 8854                    )
 8855                } else {
 8856                    self.render_edit_prediction_eager_jump_popover(
 8857                        text_bounds,
 8858                        content_origin,
 8859                        editor_snapshot,
 8860                        visible_row_range,
 8861                        scroll_top,
 8862                        scroll_bottom,
 8863                        line_height,
 8864                        scroll_pixel_position,
 8865                        target_display_point,
 8866                        editor_width,
 8867                        window,
 8868                        cx,
 8869                    )
 8870                }
 8871            }
 8872            EditPrediction::Edit {
 8873                display_mode: EditDisplayMode::Inline,
 8874                ..
 8875            } => None,
 8876            EditPrediction::Edit {
 8877                display_mode: EditDisplayMode::TabAccept,
 8878                edits,
 8879                ..
 8880            } => {
 8881                let range = &edits.first()?.0;
 8882                let target_display_point = range.end.to_display_point(editor_snapshot);
 8883
 8884                self.render_edit_prediction_end_of_line_popover(
 8885                    "Accept",
 8886                    editor_snapshot,
 8887                    visible_row_range,
 8888                    target_display_point,
 8889                    line_height,
 8890                    scroll_pixel_position,
 8891                    content_origin,
 8892                    editor_width,
 8893                    window,
 8894                    cx,
 8895                )
 8896            }
 8897            EditPrediction::Edit {
 8898                edits,
 8899                edit_preview,
 8900                display_mode: EditDisplayMode::DiffPopover,
 8901                snapshot,
 8902            } => self.render_edit_prediction_diff_popover(
 8903                text_bounds,
 8904                content_origin,
 8905                right_margin,
 8906                editor_snapshot,
 8907                visible_row_range,
 8908                line_layouts,
 8909                line_height,
 8910                scroll_position,
 8911                scroll_pixel_position,
 8912                newest_selection_head,
 8913                editor_width,
 8914                style,
 8915                edits,
 8916                edit_preview,
 8917                snapshot,
 8918                window,
 8919                cx,
 8920            ),
 8921            EditPrediction::MoveOutside { snapshot, .. } => {
 8922                let mut element = self
 8923                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8924                    .into_any();
 8925
 8926                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8927                let origin_x = text_bounds.size.width - size.width - px(30.);
 8928                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8929                element.prepaint_at(origin, window, cx);
 8930
 8931                Some((element, origin))
 8932            }
 8933        }
 8934    }
 8935
 8936    fn render_edit_prediction_modifier_jump_popover(
 8937        &mut self,
 8938        text_bounds: &Bounds<Pixels>,
 8939        content_origin: gpui::Point<Pixels>,
 8940        visible_row_range: Range<DisplayRow>,
 8941        line_layouts: &[LineWithInvisibles],
 8942        line_height: Pixels,
 8943        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8944        newest_selection_head: Option<DisplayPoint>,
 8945        target_display_point: DisplayPoint,
 8946        window: &mut Window,
 8947        cx: &mut App,
 8948    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8949        let scrolled_content_origin =
 8950            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8951
 8952        const SCROLL_PADDING_Y: Pixels = px(12.);
 8953
 8954        if target_display_point.row() < visible_row_range.start {
 8955            return self.render_edit_prediction_scroll_popover(
 8956                |_| SCROLL_PADDING_Y,
 8957                IconName::ArrowUp,
 8958                visible_row_range,
 8959                line_layouts,
 8960                newest_selection_head,
 8961                scrolled_content_origin,
 8962                window,
 8963                cx,
 8964            );
 8965        } else if target_display_point.row() >= visible_row_range.end {
 8966            return self.render_edit_prediction_scroll_popover(
 8967                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8968                IconName::ArrowDown,
 8969                visible_row_range,
 8970                line_layouts,
 8971                newest_selection_head,
 8972                scrolled_content_origin,
 8973                window,
 8974                cx,
 8975            );
 8976        }
 8977
 8978        const POLE_WIDTH: Pixels = px(2.);
 8979
 8980        let line_layout =
 8981            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8982        let target_column = target_display_point.column() as usize;
 8983
 8984        let target_x = line_layout.x_for_index(target_column);
 8985        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8986            - scroll_pixel_position.y;
 8987
 8988        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8989
 8990        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8991        border_color.l += 0.001;
 8992
 8993        let mut element = v_flex()
 8994            .items_end()
 8995            .when(flag_on_right, |el| el.items_start())
 8996            .child(if flag_on_right {
 8997                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8998                    .rounded_bl(px(0.))
 8999                    .rounded_tl(px(0.))
 9000                    .border_l_2()
 9001                    .border_color(border_color)
 9002            } else {
 9003                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9004                    .rounded_br(px(0.))
 9005                    .rounded_tr(px(0.))
 9006                    .border_r_2()
 9007                    .border_color(border_color)
 9008            })
 9009            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9010            .into_any();
 9011
 9012        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9013
 9014        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9015            - point(
 9016                if flag_on_right {
 9017                    POLE_WIDTH
 9018                } else {
 9019                    size.width - POLE_WIDTH
 9020                },
 9021                size.height - line_height,
 9022            );
 9023
 9024        origin.x = origin.x.max(content_origin.x);
 9025
 9026        element.prepaint_at(origin, window, cx);
 9027
 9028        Some((element, origin))
 9029    }
 9030
 9031    fn render_edit_prediction_scroll_popover(
 9032        &mut self,
 9033        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9034        scroll_icon: IconName,
 9035        visible_row_range: Range<DisplayRow>,
 9036        line_layouts: &[LineWithInvisibles],
 9037        newest_selection_head: Option<DisplayPoint>,
 9038        scrolled_content_origin: gpui::Point<Pixels>,
 9039        window: &mut Window,
 9040        cx: &mut App,
 9041    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9042        let mut element = self
 9043            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9044            .into_any();
 9045
 9046        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9047
 9048        let cursor = newest_selection_head?;
 9049        let cursor_row_layout =
 9050            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9051        let cursor_column = cursor.column() as usize;
 9052
 9053        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9054
 9055        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9056
 9057        element.prepaint_at(origin, window, cx);
 9058        Some((element, origin))
 9059    }
 9060
 9061    fn render_edit_prediction_eager_jump_popover(
 9062        &mut self,
 9063        text_bounds: &Bounds<Pixels>,
 9064        content_origin: gpui::Point<Pixels>,
 9065        editor_snapshot: &EditorSnapshot,
 9066        visible_row_range: Range<DisplayRow>,
 9067        scroll_top: ScrollOffset,
 9068        scroll_bottom: ScrollOffset,
 9069        line_height: Pixels,
 9070        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9071        target_display_point: DisplayPoint,
 9072        editor_width: Pixels,
 9073        window: &mut Window,
 9074        cx: &mut App,
 9075    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9076        if target_display_point.row().as_f64() < scroll_top {
 9077            let mut element = self
 9078                .render_edit_prediction_line_popover(
 9079                    "Jump to Edit",
 9080                    Some(IconName::ArrowUp),
 9081                    window,
 9082                    cx,
 9083                )
 9084                .into_any();
 9085
 9086            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9087            let offset = point(
 9088                (text_bounds.size.width - size.width) / 2.,
 9089                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9090            );
 9091
 9092            let origin = text_bounds.origin + offset;
 9093            element.prepaint_at(origin, window, cx);
 9094            Some((element, origin))
 9095        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9096            let mut element = self
 9097                .render_edit_prediction_line_popover(
 9098                    "Jump to Edit",
 9099                    Some(IconName::ArrowDown),
 9100                    window,
 9101                    cx,
 9102                )
 9103                .into_any();
 9104
 9105            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9106            let offset = point(
 9107                (text_bounds.size.width - size.width) / 2.,
 9108                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9109            );
 9110
 9111            let origin = text_bounds.origin + offset;
 9112            element.prepaint_at(origin, window, cx);
 9113            Some((element, origin))
 9114        } else {
 9115            self.render_edit_prediction_end_of_line_popover(
 9116                "Jump to Edit",
 9117                editor_snapshot,
 9118                visible_row_range,
 9119                target_display_point,
 9120                line_height,
 9121                scroll_pixel_position,
 9122                content_origin,
 9123                editor_width,
 9124                window,
 9125                cx,
 9126            )
 9127        }
 9128    }
 9129
 9130    fn render_edit_prediction_end_of_line_popover(
 9131        self: &mut Editor,
 9132        label: &'static str,
 9133        editor_snapshot: &EditorSnapshot,
 9134        visible_row_range: Range<DisplayRow>,
 9135        target_display_point: DisplayPoint,
 9136        line_height: Pixels,
 9137        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9138        content_origin: gpui::Point<Pixels>,
 9139        editor_width: Pixels,
 9140        window: &mut Window,
 9141        cx: &mut App,
 9142    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9143        let target_line_end = DisplayPoint::new(
 9144            target_display_point.row(),
 9145            editor_snapshot.line_len(target_display_point.row()),
 9146        );
 9147
 9148        let mut element = self
 9149            .render_edit_prediction_line_popover(label, None, window, cx)
 9150            .into_any();
 9151
 9152        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9153
 9154        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9155
 9156        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9157        let mut origin = start_point
 9158            + line_origin
 9159            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9160        origin.x = origin.x.max(content_origin.x);
 9161
 9162        let max_x = content_origin.x + editor_width - size.width;
 9163
 9164        if origin.x > max_x {
 9165            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9166
 9167            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9168                origin.y += offset;
 9169                IconName::ArrowUp
 9170            } else {
 9171                origin.y -= offset;
 9172                IconName::ArrowDown
 9173            };
 9174
 9175            element = self
 9176                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9177                .into_any();
 9178
 9179            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9180
 9181            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9182        }
 9183
 9184        element.prepaint_at(origin, window, cx);
 9185        Some((element, origin))
 9186    }
 9187
 9188    fn render_edit_prediction_diff_popover(
 9189        self: &Editor,
 9190        text_bounds: &Bounds<Pixels>,
 9191        content_origin: gpui::Point<Pixels>,
 9192        right_margin: Pixels,
 9193        editor_snapshot: &EditorSnapshot,
 9194        visible_row_range: Range<DisplayRow>,
 9195        line_layouts: &[LineWithInvisibles],
 9196        line_height: Pixels,
 9197        scroll_position: gpui::Point<ScrollOffset>,
 9198        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9199        newest_selection_head: Option<DisplayPoint>,
 9200        editor_width: Pixels,
 9201        style: &EditorStyle,
 9202        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9203        edit_preview: &Option<language::EditPreview>,
 9204        snapshot: &language::BufferSnapshot,
 9205        window: &mut Window,
 9206        cx: &mut App,
 9207    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9208        let edit_start = edits
 9209            .first()
 9210            .unwrap()
 9211            .0
 9212            .start
 9213            .to_display_point(editor_snapshot);
 9214        let edit_end = edits
 9215            .last()
 9216            .unwrap()
 9217            .0
 9218            .end
 9219            .to_display_point(editor_snapshot);
 9220
 9221        let is_visible = visible_row_range.contains(&edit_start.row())
 9222            || visible_row_range.contains(&edit_end.row());
 9223        if !is_visible {
 9224            return None;
 9225        }
 9226
 9227        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9228            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9229        } else {
 9230            // Fallback for providers without edit_preview
 9231            crate::edit_prediction_fallback_text(edits, cx)
 9232        };
 9233
 9234        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9235        let line_count = highlighted_edits.text.lines().count();
 9236
 9237        const BORDER_WIDTH: Pixels = px(1.);
 9238
 9239        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9240        let has_keybind = keybind.is_some();
 9241
 9242        let mut element = h_flex()
 9243            .items_start()
 9244            .child(
 9245                h_flex()
 9246                    .bg(cx.theme().colors().editor_background)
 9247                    .border(BORDER_WIDTH)
 9248                    .shadow_xs()
 9249                    .border_color(cx.theme().colors().border)
 9250                    .rounded_l_lg()
 9251                    .when(line_count > 1, |el| el.rounded_br_lg())
 9252                    .pr_1()
 9253                    .child(styled_text),
 9254            )
 9255            .child(
 9256                h_flex()
 9257                    .h(line_height + BORDER_WIDTH * 2.)
 9258                    .px_1p5()
 9259                    .gap_1()
 9260                    // Workaround: For some reason, there's a gap if we don't do this
 9261                    .ml(-BORDER_WIDTH)
 9262                    .shadow(vec![gpui::BoxShadow {
 9263                        color: gpui::black().opacity(0.05),
 9264                        offset: point(px(1.), px(1.)),
 9265                        blur_radius: px(2.),
 9266                        spread_radius: px(0.),
 9267                    }])
 9268                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9269                    .border(BORDER_WIDTH)
 9270                    .border_color(cx.theme().colors().border)
 9271                    .rounded_r_lg()
 9272                    .id("edit_prediction_diff_popover_keybind")
 9273                    .when(!has_keybind, |el| {
 9274                        let status_colors = cx.theme().status();
 9275
 9276                        el.bg(status_colors.error_background)
 9277                            .border_color(status_colors.error.opacity(0.6))
 9278                            .child(Icon::new(IconName::Info).color(Color::Error))
 9279                            .cursor_default()
 9280                            .hoverable_tooltip(move |_window, cx| {
 9281                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9282                            })
 9283                    })
 9284                    .children(keybind),
 9285            )
 9286            .into_any();
 9287
 9288        let longest_row =
 9289            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9290        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9291            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9292        } else {
 9293            layout_line(
 9294                longest_row,
 9295                editor_snapshot,
 9296                style,
 9297                editor_width,
 9298                |_| false,
 9299                window,
 9300                cx,
 9301            )
 9302            .width
 9303        };
 9304
 9305        let viewport_bounds =
 9306            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9307                right: -right_margin,
 9308                ..Default::default()
 9309            });
 9310
 9311        let x_after_longest = Pixels::from(
 9312            ScrollPixelOffset::from(
 9313                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9314            ) - scroll_pixel_position.x,
 9315        );
 9316
 9317        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9318
 9319        // Fully visible if it can be displayed within the window (allow overlapping other
 9320        // panes). However, this is only allowed if the popover starts within text_bounds.
 9321        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9322            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9323
 9324        let mut origin = if can_position_to_the_right {
 9325            point(
 9326                x_after_longest,
 9327                text_bounds.origin.y
 9328                    + Pixels::from(
 9329                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9330                            - scroll_pixel_position.y,
 9331                    ),
 9332            )
 9333        } else {
 9334            let cursor_row = newest_selection_head.map(|head| head.row());
 9335            let above_edit = edit_start
 9336                .row()
 9337                .0
 9338                .checked_sub(line_count as u32)
 9339                .map(DisplayRow);
 9340            let below_edit = Some(edit_end.row() + 1);
 9341            let above_cursor =
 9342                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9343            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9344
 9345            // Place the edit popover adjacent to the edit if there is a location
 9346            // available that is onscreen and does not obscure the cursor. Otherwise,
 9347            // place it adjacent to the cursor.
 9348            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9349                .into_iter()
 9350                .flatten()
 9351                .find(|&start_row| {
 9352                    let end_row = start_row + line_count as u32;
 9353                    visible_row_range.contains(&start_row)
 9354                        && visible_row_range.contains(&end_row)
 9355                        && cursor_row
 9356                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9357                })?;
 9358
 9359            content_origin
 9360                + point(
 9361                    Pixels::from(-scroll_pixel_position.x),
 9362                    Pixels::from(
 9363                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9364                    ),
 9365                )
 9366        };
 9367
 9368        origin.x -= BORDER_WIDTH;
 9369
 9370        window.defer_draw(element, origin, 1);
 9371
 9372        // Do not return an element, since it will already be drawn due to defer_draw.
 9373        None
 9374    }
 9375
 9376    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9377        px(30.)
 9378    }
 9379
 9380    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9381        if self.read_only(cx) {
 9382            cx.theme().players().read_only()
 9383        } else {
 9384            self.style.as_ref().unwrap().local_player
 9385        }
 9386    }
 9387
 9388    fn render_edit_prediction_accept_keybind(
 9389        &self,
 9390        window: &mut Window,
 9391        cx: &mut App,
 9392    ) -> Option<AnyElement> {
 9393        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9394        let accept_keystroke = accept_binding.keystroke()?;
 9395
 9396        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9397
 9398        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9399            Color::Accent
 9400        } else {
 9401            Color::Muted
 9402        };
 9403
 9404        h_flex()
 9405            .px_0p5()
 9406            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9407            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9408            .text_size(TextSize::XSmall.rems(cx))
 9409            .child(h_flex().children(ui::render_modifiers(
 9410                accept_keystroke.modifiers(),
 9411                PlatformStyle::platform(),
 9412                Some(modifiers_color),
 9413                Some(IconSize::XSmall.rems().into()),
 9414                true,
 9415            )))
 9416            .when(is_platform_style_mac, |parent| {
 9417                parent.child(accept_keystroke.key().to_string())
 9418            })
 9419            .when(!is_platform_style_mac, |parent| {
 9420                parent.child(
 9421                    Key::new(
 9422                        util::capitalize(accept_keystroke.key()),
 9423                        Some(Color::Default),
 9424                    )
 9425                    .size(Some(IconSize::XSmall.rems().into())),
 9426                )
 9427            })
 9428            .into_any()
 9429            .into()
 9430    }
 9431
 9432    fn render_edit_prediction_line_popover(
 9433        &self,
 9434        label: impl Into<SharedString>,
 9435        icon: Option<IconName>,
 9436        window: &mut Window,
 9437        cx: &mut App,
 9438    ) -> Stateful<Div> {
 9439        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9440
 9441        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9442        let has_keybind = keybind.is_some();
 9443
 9444        h_flex()
 9445            .id("ep-line-popover")
 9446            .py_0p5()
 9447            .pl_1()
 9448            .pr(padding_right)
 9449            .gap_1()
 9450            .rounded_md()
 9451            .border_1()
 9452            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9453            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9454            .shadow_xs()
 9455            .when(!has_keybind, |el| {
 9456                let status_colors = cx.theme().status();
 9457
 9458                el.bg(status_colors.error_background)
 9459                    .border_color(status_colors.error.opacity(0.6))
 9460                    .pl_2()
 9461                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9462                    .cursor_default()
 9463                    .hoverable_tooltip(move |_window, cx| {
 9464                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9465                    })
 9466            })
 9467            .children(keybind)
 9468            .child(
 9469                Label::new(label)
 9470                    .size(LabelSize::Small)
 9471                    .when(!has_keybind, |el| {
 9472                        el.color(cx.theme().status().error.into()).strikethrough()
 9473                    }),
 9474            )
 9475            .when(!has_keybind, |el| {
 9476                el.child(
 9477                    h_flex().ml_1().child(
 9478                        Icon::new(IconName::Info)
 9479                            .size(IconSize::Small)
 9480                            .color(cx.theme().status().error.into()),
 9481                    ),
 9482                )
 9483            })
 9484            .when_some(icon, |element, icon| {
 9485                element.child(
 9486                    div()
 9487                        .mt(px(1.5))
 9488                        .child(Icon::new(icon).size(IconSize::Small)),
 9489                )
 9490            })
 9491    }
 9492
 9493    fn render_edit_prediction_jump_outside_popover(
 9494        &self,
 9495        snapshot: &BufferSnapshot,
 9496        window: &mut Window,
 9497        cx: &mut App,
 9498    ) -> Stateful<Div> {
 9499        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9500        let has_keybind = keybind.is_some();
 9501
 9502        let file_name = snapshot
 9503            .file()
 9504            .map(|file| SharedString::new(file.file_name(cx)))
 9505            .unwrap_or(SharedString::new_static("untitled"));
 9506
 9507        h_flex()
 9508            .id("ep-jump-outside-popover")
 9509            .py_1()
 9510            .px_2()
 9511            .gap_1()
 9512            .rounded_md()
 9513            .border_1()
 9514            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9515            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9516            .shadow_xs()
 9517            .when(!has_keybind, |el| {
 9518                let status_colors = cx.theme().status();
 9519
 9520                el.bg(status_colors.error_background)
 9521                    .border_color(status_colors.error.opacity(0.6))
 9522                    .pl_2()
 9523                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9524                    .cursor_default()
 9525                    .hoverable_tooltip(move |_window, cx| {
 9526                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9527                    })
 9528            })
 9529            .children(keybind)
 9530            .child(
 9531                Label::new(file_name)
 9532                    .size(LabelSize::Small)
 9533                    .buffer_font(cx)
 9534                    .when(!has_keybind, |el| {
 9535                        el.color(cx.theme().status().error.into()).strikethrough()
 9536                    }),
 9537            )
 9538            .when(!has_keybind, |el| {
 9539                el.child(
 9540                    h_flex().ml_1().child(
 9541                        Icon::new(IconName::Info)
 9542                            .size(IconSize::Small)
 9543                            .color(cx.theme().status().error.into()),
 9544                    ),
 9545                )
 9546            })
 9547            .child(
 9548                div()
 9549                    .mt(px(1.5))
 9550                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9551            )
 9552    }
 9553
 9554    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9555        let accent_color = cx.theme().colors().text_accent;
 9556        let editor_bg_color = cx.theme().colors().editor_background;
 9557        editor_bg_color.blend(accent_color.opacity(0.1))
 9558    }
 9559
 9560    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9561        let accent_color = cx.theme().colors().text_accent;
 9562        let editor_bg_color = cx.theme().colors().editor_background;
 9563        editor_bg_color.blend(accent_color.opacity(0.6))
 9564    }
 9565    fn get_prediction_provider_icon_name(
 9566        provider: &Option<RegisteredEditPredictionProvider>,
 9567    ) -> IconName {
 9568        match provider {
 9569            Some(provider) => match provider.provider.name() {
 9570                "copilot" => IconName::Copilot,
 9571                "supermaven" => IconName::Supermaven,
 9572                _ => IconName::ZedPredict,
 9573            },
 9574            None => IconName::ZedPredict,
 9575        }
 9576    }
 9577
 9578    fn render_edit_prediction_cursor_popover(
 9579        &self,
 9580        min_width: Pixels,
 9581        max_width: Pixels,
 9582        cursor_point: Point,
 9583        style: &EditorStyle,
 9584        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9585        _window: &Window,
 9586        cx: &mut Context<Editor>,
 9587    ) -> Option<AnyElement> {
 9588        let provider = self.edit_prediction_provider.as_ref()?;
 9589        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9590
 9591        let is_refreshing = provider.provider.is_refreshing(cx);
 9592
 9593        fn pending_completion_container(icon: IconName) -> Div {
 9594            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9595        }
 9596
 9597        let completion = match &self.active_edit_prediction {
 9598            Some(prediction) => {
 9599                if !self.has_visible_completions_menu() {
 9600                    const RADIUS: Pixels = px(6.);
 9601                    const BORDER_WIDTH: Pixels = px(1.);
 9602
 9603                    return Some(
 9604                        h_flex()
 9605                            .elevation_2(cx)
 9606                            .border(BORDER_WIDTH)
 9607                            .border_color(cx.theme().colors().border)
 9608                            .when(accept_keystroke.is_none(), |el| {
 9609                                el.border_color(cx.theme().status().error)
 9610                            })
 9611                            .rounded(RADIUS)
 9612                            .rounded_tl(px(0.))
 9613                            .overflow_hidden()
 9614                            .child(div().px_1p5().child(match &prediction.completion {
 9615                                EditPrediction::MoveWithin { target, snapshot } => {
 9616                                    use text::ToPoint as _;
 9617                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9618                                    {
 9619                                        Icon::new(IconName::ZedPredictDown)
 9620                                    } else {
 9621                                        Icon::new(IconName::ZedPredictUp)
 9622                                    }
 9623                                }
 9624                                EditPrediction::MoveOutside { .. } => {
 9625                                    // TODO [zeta2] custom icon for external jump?
 9626                                    Icon::new(provider_icon)
 9627                                }
 9628                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9629                            }))
 9630                            .child(
 9631                                h_flex()
 9632                                    .gap_1()
 9633                                    .py_1()
 9634                                    .px_2()
 9635                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9636                                    .border_l_1()
 9637                                    .border_color(cx.theme().colors().border)
 9638                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9639                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9640                                        el.child(
 9641                                            Label::new("Hold")
 9642                                                .size(LabelSize::Small)
 9643                                                .when(accept_keystroke.is_none(), |el| {
 9644                                                    el.strikethrough()
 9645                                                })
 9646                                                .line_height_style(LineHeightStyle::UiLabel),
 9647                                        )
 9648                                    })
 9649                                    .id("edit_prediction_cursor_popover_keybind")
 9650                                    .when(accept_keystroke.is_none(), |el| {
 9651                                        let status_colors = cx.theme().status();
 9652
 9653                                        el.bg(status_colors.error_background)
 9654                                            .border_color(status_colors.error.opacity(0.6))
 9655                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9656                                            .cursor_default()
 9657                                            .hoverable_tooltip(move |_window, cx| {
 9658                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9659                                                    .into()
 9660                                            })
 9661                                    })
 9662                                    .when_some(
 9663                                        accept_keystroke.as_ref(),
 9664                                        |el, accept_keystroke| {
 9665                                            el.child(h_flex().children(ui::render_modifiers(
 9666                                                accept_keystroke.modifiers(),
 9667                                                PlatformStyle::platform(),
 9668                                                Some(Color::Default),
 9669                                                Some(IconSize::XSmall.rems().into()),
 9670                                                false,
 9671                                            )))
 9672                                        },
 9673                                    ),
 9674                            )
 9675                            .into_any(),
 9676                    );
 9677                }
 9678
 9679                self.render_edit_prediction_cursor_popover_preview(
 9680                    prediction,
 9681                    cursor_point,
 9682                    style,
 9683                    cx,
 9684                )?
 9685            }
 9686
 9687            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9688                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9689                    stale_completion,
 9690                    cursor_point,
 9691                    style,
 9692                    cx,
 9693                )?,
 9694
 9695                None => pending_completion_container(provider_icon)
 9696                    .child(Label::new("...").size(LabelSize::Small)),
 9697            },
 9698
 9699            None => pending_completion_container(provider_icon)
 9700                .child(Label::new("...").size(LabelSize::Small)),
 9701        };
 9702
 9703        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9704            completion
 9705                .with_animation(
 9706                    "loading-completion",
 9707                    Animation::new(Duration::from_secs(2))
 9708                        .repeat()
 9709                        .with_easing(pulsating_between(0.4, 0.8)),
 9710                    |label, delta| label.opacity(delta),
 9711                )
 9712                .into_any_element()
 9713        } else {
 9714            completion.into_any_element()
 9715        };
 9716
 9717        let has_completion = self.active_edit_prediction.is_some();
 9718
 9719        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9720        Some(
 9721            h_flex()
 9722                .min_w(min_width)
 9723                .max_w(max_width)
 9724                .flex_1()
 9725                .elevation_2(cx)
 9726                .border_color(cx.theme().colors().border)
 9727                .child(
 9728                    div()
 9729                        .flex_1()
 9730                        .py_1()
 9731                        .px_2()
 9732                        .overflow_hidden()
 9733                        .child(completion),
 9734                )
 9735                .when_some(accept_keystroke, |el, accept_keystroke| {
 9736                    if !accept_keystroke.modifiers().modified() {
 9737                        return el;
 9738                    }
 9739
 9740                    el.child(
 9741                        h_flex()
 9742                            .h_full()
 9743                            .border_l_1()
 9744                            .rounded_r_lg()
 9745                            .border_color(cx.theme().colors().border)
 9746                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9747                            .gap_1()
 9748                            .py_1()
 9749                            .px_2()
 9750                            .child(
 9751                                h_flex()
 9752                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9753                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9754                                    .child(h_flex().children(ui::render_modifiers(
 9755                                        accept_keystroke.modifiers(),
 9756                                        PlatformStyle::platform(),
 9757                                        Some(if !has_completion {
 9758                                            Color::Muted
 9759                                        } else {
 9760                                            Color::Default
 9761                                        }),
 9762                                        None,
 9763                                        false,
 9764                                    ))),
 9765                            )
 9766                            .child(Label::new("Preview").into_any_element())
 9767                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9768                    )
 9769                })
 9770                .into_any(),
 9771        )
 9772    }
 9773
 9774    fn render_edit_prediction_cursor_popover_preview(
 9775        &self,
 9776        completion: &EditPredictionState,
 9777        cursor_point: Point,
 9778        style: &EditorStyle,
 9779        cx: &mut Context<Editor>,
 9780    ) -> Option<Div> {
 9781        use text::ToPoint as _;
 9782
 9783        fn render_relative_row_jump(
 9784            prefix: impl Into<String>,
 9785            current_row: u32,
 9786            target_row: u32,
 9787        ) -> Div {
 9788            let (row_diff, arrow) = if target_row < current_row {
 9789                (current_row - target_row, IconName::ArrowUp)
 9790            } else {
 9791                (target_row - current_row, IconName::ArrowDown)
 9792            };
 9793
 9794            h_flex()
 9795                .child(
 9796                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9797                        .color(Color::Muted)
 9798                        .size(LabelSize::Small),
 9799                )
 9800                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9801        }
 9802
 9803        let supports_jump = self
 9804            .edit_prediction_provider
 9805            .as_ref()
 9806            .map(|provider| provider.provider.supports_jump_to_edit())
 9807            .unwrap_or(true);
 9808
 9809        match &completion.completion {
 9810            EditPrediction::MoveWithin {
 9811                target, snapshot, ..
 9812            } => {
 9813                if !supports_jump {
 9814                    return None;
 9815                }
 9816
 9817                Some(
 9818                    h_flex()
 9819                        .px_2()
 9820                        .gap_2()
 9821                        .flex_1()
 9822                        .child(
 9823                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9824                                Icon::new(IconName::ZedPredictDown)
 9825                            } else {
 9826                                Icon::new(IconName::ZedPredictUp)
 9827                            },
 9828                        )
 9829                        .child(Label::new("Jump to Edit")),
 9830                )
 9831            }
 9832            EditPrediction::MoveOutside { snapshot, .. } => {
 9833                let file_name = snapshot
 9834                    .file()
 9835                    .map(|file| file.file_name(cx))
 9836                    .unwrap_or("untitled");
 9837                Some(
 9838                    h_flex()
 9839                        .px_2()
 9840                        .gap_2()
 9841                        .flex_1()
 9842                        .child(Icon::new(IconName::ZedPredict))
 9843                        .child(Label::new(format!("Jump to {file_name}"))),
 9844                )
 9845            }
 9846            EditPrediction::Edit {
 9847                edits,
 9848                edit_preview,
 9849                snapshot,
 9850                display_mode: _,
 9851            } => {
 9852                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9853
 9854                let (highlighted_edits, has_more_lines) =
 9855                    if let Some(edit_preview) = edit_preview.as_ref() {
 9856                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9857                            .first_line_preview()
 9858                    } else {
 9859                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9860                    };
 9861
 9862                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9863                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9864
 9865                let preview = h_flex()
 9866                    .gap_1()
 9867                    .min_w_16()
 9868                    .child(styled_text)
 9869                    .when(has_more_lines, |parent| parent.child(""));
 9870
 9871                let left = if supports_jump && first_edit_row != cursor_point.row {
 9872                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9873                        .into_any_element()
 9874                } else {
 9875                    let icon_name =
 9876                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9877                    Icon::new(icon_name).into_any_element()
 9878                };
 9879
 9880                Some(
 9881                    h_flex()
 9882                        .h_full()
 9883                        .flex_1()
 9884                        .gap_2()
 9885                        .pr_1()
 9886                        .overflow_x_hidden()
 9887                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9888                        .child(left)
 9889                        .child(preview),
 9890                )
 9891            }
 9892        }
 9893    }
 9894
 9895    pub fn render_context_menu(
 9896        &self,
 9897        style: &EditorStyle,
 9898        max_height_in_lines: u32,
 9899        window: &mut Window,
 9900        cx: &mut Context<Editor>,
 9901    ) -> Option<AnyElement> {
 9902        let menu = self.context_menu.borrow();
 9903        let menu = menu.as_ref()?;
 9904        if !menu.visible() {
 9905            return None;
 9906        };
 9907        Some(menu.render(style, max_height_in_lines, window, cx))
 9908    }
 9909
 9910    fn render_context_menu_aside(
 9911        &mut self,
 9912        max_size: Size<Pixels>,
 9913        window: &mut Window,
 9914        cx: &mut Context<Editor>,
 9915    ) -> Option<AnyElement> {
 9916        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9917            if menu.visible() {
 9918                menu.render_aside(max_size, window, cx)
 9919            } else {
 9920                None
 9921            }
 9922        })
 9923    }
 9924
 9925    fn hide_context_menu(
 9926        &mut self,
 9927        window: &mut Window,
 9928        cx: &mut Context<Self>,
 9929    ) -> Option<CodeContextMenu> {
 9930        cx.notify();
 9931        self.completion_tasks.clear();
 9932        let context_menu = self.context_menu.borrow_mut().take();
 9933        self.stale_edit_prediction_in_menu.take();
 9934        self.update_visible_edit_prediction(window, cx);
 9935        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9936            && let Some(completion_provider) = &self.completion_provider
 9937        {
 9938            completion_provider.selection_changed(None, window, cx);
 9939        }
 9940        context_menu
 9941    }
 9942
 9943    fn show_snippet_choices(
 9944        &mut self,
 9945        choices: &Vec<String>,
 9946        selection: Range<Anchor>,
 9947        cx: &mut Context<Self>,
 9948    ) {
 9949        let Some((_, buffer, _)) = self
 9950            .buffer()
 9951            .read(cx)
 9952            .excerpt_containing(selection.start, cx)
 9953        else {
 9954            return;
 9955        };
 9956        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9957        else {
 9958            return;
 9959        };
 9960        if buffer != end_buffer {
 9961            log::error!("expected anchor range to have matching buffer IDs");
 9962            return;
 9963        }
 9964
 9965        let id = post_inc(&mut self.next_completion_id);
 9966        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9967        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9968            CompletionsMenu::new_snippet_choices(
 9969                id,
 9970                true,
 9971                choices,
 9972                selection,
 9973                buffer,
 9974                snippet_sort_order,
 9975            ),
 9976        ));
 9977    }
 9978
 9979    pub fn insert_snippet(
 9980        &mut self,
 9981        insertion_ranges: &[Range<MultiBufferOffset>],
 9982        snippet: Snippet,
 9983        window: &mut Window,
 9984        cx: &mut Context<Self>,
 9985    ) -> Result<()> {
 9986        struct Tabstop<T> {
 9987            is_end_tabstop: bool,
 9988            ranges: Vec<Range<T>>,
 9989            choices: Option<Vec<String>>,
 9990        }
 9991
 9992        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9993            let snippet_text: Arc<str> = snippet.text.clone().into();
 9994            let edits = insertion_ranges
 9995                .iter()
 9996                .cloned()
 9997                .map(|range| (range, snippet_text.clone()));
 9998            let autoindent_mode = AutoindentMode::Block {
 9999                original_indent_columns: Vec::new(),
10000            };
10001            buffer.edit(edits, Some(autoindent_mode), cx);
10002
10003            let snapshot = &*buffer.read(cx);
10004            let snippet = &snippet;
10005            snippet
10006                .tabstops
10007                .iter()
10008                .map(|tabstop| {
10009                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10010                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10011                    });
10012                    let mut tabstop_ranges = tabstop
10013                        .ranges
10014                        .iter()
10015                        .flat_map(|tabstop_range| {
10016                            let mut delta = 0_isize;
10017                            insertion_ranges.iter().map(move |insertion_range| {
10018                                let insertion_start = insertion_range.start + delta;
10019                                delta += snippet.text.len() as isize
10020                                    - (insertion_range.end - insertion_range.start) as isize;
10021
10022                                let start =
10023                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10024                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10025                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10026                            })
10027                        })
10028                        .collect::<Vec<_>>();
10029                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10030
10031                    Tabstop {
10032                        is_end_tabstop,
10033                        ranges: tabstop_ranges,
10034                        choices: tabstop.choices.clone(),
10035                    }
10036                })
10037                .collect::<Vec<_>>()
10038        });
10039        if let Some(tabstop) = tabstops.first() {
10040            self.change_selections(Default::default(), window, cx, |s| {
10041                // Reverse order so that the first range is the newest created selection.
10042                // Completions will use it and autoscroll will prioritize it.
10043                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10044            });
10045
10046            if let Some(choices) = &tabstop.choices
10047                && let Some(selection) = tabstop.ranges.first()
10048            {
10049                self.show_snippet_choices(choices, selection.clone(), cx)
10050            }
10051
10052            // If we're already at the last tabstop and it's at the end of the snippet,
10053            // we're done, we don't need to keep the state around.
10054            if !tabstop.is_end_tabstop {
10055                let choices = tabstops
10056                    .iter()
10057                    .map(|tabstop| tabstop.choices.clone())
10058                    .collect();
10059
10060                let ranges = tabstops
10061                    .into_iter()
10062                    .map(|tabstop| tabstop.ranges)
10063                    .collect::<Vec<_>>();
10064
10065                self.snippet_stack.push(SnippetState {
10066                    active_index: 0,
10067                    ranges,
10068                    choices,
10069                });
10070            }
10071
10072            // Check whether the just-entered snippet ends with an auto-closable bracket.
10073            if self.autoclose_regions.is_empty() {
10074                let snapshot = self.buffer.read(cx).snapshot(cx);
10075                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10076                    let selection_head = selection.head();
10077                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10078                        continue;
10079                    };
10080
10081                    let mut bracket_pair = None;
10082                    let max_lookup_length = scope
10083                        .brackets()
10084                        .map(|(pair, _)| {
10085                            pair.start
10086                                .as_str()
10087                                .chars()
10088                                .count()
10089                                .max(pair.end.as_str().chars().count())
10090                        })
10091                        .max();
10092                    if let Some(max_lookup_length) = max_lookup_length {
10093                        let next_text = snapshot
10094                            .chars_at(selection_head)
10095                            .take(max_lookup_length)
10096                            .collect::<String>();
10097                        let prev_text = snapshot
10098                            .reversed_chars_at(selection_head)
10099                            .take(max_lookup_length)
10100                            .collect::<String>();
10101
10102                        for (pair, enabled) in scope.brackets() {
10103                            if enabled
10104                                && pair.close
10105                                && prev_text.starts_with(pair.start.as_str())
10106                                && next_text.starts_with(pair.end.as_str())
10107                            {
10108                                bracket_pair = Some(pair.clone());
10109                                break;
10110                            }
10111                        }
10112                    }
10113
10114                    if let Some(pair) = bracket_pair {
10115                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10116                        let autoclose_enabled =
10117                            self.use_autoclose && snapshot_settings.use_autoclose;
10118                        if autoclose_enabled {
10119                            let start = snapshot.anchor_after(selection_head);
10120                            let end = snapshot.anchor_after(selection_head);
10121                            self.autoclose_regions.push(AutocloseRegion {
10122                                selection_id: selection.id,
10123                                range: start..end,
10124                                pair,
10125                            });
10126                        }
10127                    }
10128                }
10129            }
10130        }
10131        Ok(())
10132    }
10133
10134    pub fn move_to_next_snippet_tabstop(
10135        &mut self,
10136        window: &mut Window,
10137        cx: &mut Context<Self>,
10138    ) -> bool {
10139        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10140    }
10141
10142    pub fn move_to_prev_snippet_tabstop(
10143        &mut self,
10144        window: &mut Window,
10145        cx: &mut Context<Self>,
10146    ) -> bool {
10147        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10148    }
10149
10150    pub fn move_to_snippet_tabstop(
10151        &mut self,
10152        bias: Bias,
10153        window: &mut Window,
10154        cx: &mut Context<Self>,
10155    ) -> bool {
10156        if let Some(mut snippet) = self.snippet_stack.pop() {
10157            match bias {
10158                Bias::Left => {
10159                    if snippet.active_index > 0 {
10160                        snippet.active_index -= 1;
10161                    } else {
10162                        self.snippet_stack.push(snippet);
10163                        return false;
10164                    }
10165                }
10166                Bias::Right => {
10167                    if snippet.active_index + 1 < snippet.ranges.len() {
10168                        snippet.active_index += 1;
10169                    } else {
10170                        self.snippet_stack.push(snippet);
10171                        return false;
10172                    }
10173                }
10174            }
10175            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10176                self.change_selections(Default::default(), window, cx, |s| {
10177                    // Reverse order so that the first range is the newest created selection.
10178                    // Completions will use it and autoscroll will prioritize it.
10179                    s.select_ranges(current_ranges.iter().rev().cloned())
10180                });
10181
10182                if let Some(choices) = &snippet.choices[snippet.active_index]
10183                    && let Some(selection) = current_ranges.first()
10184                {
10185                    self.show_snippet_choices(choices, selection.clone(), cx);
10186                }
10187
10188                // If snippet state is not at the last tabstop, push it back on the stack
10189                if snippet.active_index + 1 < snippet.ranges.len() {
10190                    self.snippet_stack.push(snippet);
10191                }
10192                return true;
10193            }
10194        }
10195
10196        false
10197    }
10198
10199    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10200        self.transact(window, cx, |this, window, cx| {
10201            this.select_all(&SelectAll, window, cx);
10202            this.insert("", window, cx);
10203        });
10204    }
10205
10206    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10207        if self.read_only(cx) {
10208            return;
10209        }
10210        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10211        self.transact(window, cx, |this, window, cx| {
10212            this.select_autoclose_pair(window, cx);
10213
10214            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10215
10216            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10217            if !this.linked_edit_ranges.is_empty() {
10218                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10219                let snapshot = this.buffer.read(cx).snapshot(cx);
10220
10221                for selection in selections.iter() {
10222                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10223                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10224                    if selection_start.buffer_id != selection_end.buffer_id {
10225                        continue;
10226                    }
10227                    if let Some(ranges) =
10228                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10229                    {
10230                        for (buffer, entries) in ranges {
10231                            linked_ranges.entry(buffer).or_default().extend(entries);
10232                        }
10233                    }
10234                }
10235            }
10236
10237            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10238            for selection in &mut selections {
10239                if selection.is_empty() {
10240                    let old_head = selection.head();
10241                    let mut new_head =
10242                        movement::left(&display_map, old_head.to_display_point(&display_map))
10243                            .to_point(&display_map);
10244                    if let Some((buffer, line_buffer_range)) = display_map
10245                        .buffer_snapshot()
10246                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10247                    {
10248                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10249                        let indent_len = match indent_size.kind {
10250                            IndentKind::Space => {
10251                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10252                            }
10253                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10254                        };
10255                        if old_head.column <= indent_size.len && old_head.column > 0 {
10256                            let indent_len = indent_len.get();
10257                            new_head = cmp::min(
10258                                new_head,
10259                                MultiBufferPoint::new(
10260                                    old_head.row,
10261                                    ((old_head.column - 1) / indent_len) * indent_len,
10262                                ),
10263                            );
10264                        }
10265                    }
10266
10267                    selection.set_head(new_head, SelectionGoal::None);
10268                }
10269            }
10270
10271            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10272            this.insert("", window, cx);
10273            let empty_str: Arc<str> = Arc::from("");
10274            for (buffer, edits) in linked_ranges {
10275                let snapshot = buffer.read(cx).snapshot();
10276                use text::ToPoint as TP;
10277
10278                let edits = edits
10279                    .into_iter()
10280                    .map(|range| {
10281                        let end_point = TP::to_point(&range.end, &snapshot);
10282                        let mut start_point = TP::to_point(&range.start, &snapshot);
10283
10284                        if end_point == start_point {
10285                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10286                                .saturating_sub(1);
10287                            start_point =
10288                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10289                        };
10290
10291                        (start_point..end_point, empty_str.clone())
10292                    })
10293                    .sorted_by_key(|(range, _)| range.start)
10294                    .collect::<Vec<_>>();
10295                buffer.update(cx, |this, cx| {
10296                    this.edit(edits, None, cx);
10297                })
10298            }
10299            this.refresh_edit_prediction(true, false, window, cx);
10300            refresh_linked_ranges(this, window, cx);
10301        });
10302    }
10303
10304    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10305        if self.read_only(cx) {
10306            return;
10307        }
10308        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10309        self.transact(window, cx, |this, window, cx| {
10310            this.change_selections(Default::default(), window, cx, |s| {
10311                s.move_with(|map, selection| {
10312                    if selection.is_empty() {
10313                        let cursor = movement::right(map, selection.head());
10314                        selection.end = cursor;
10315                        selection.reversed = true;
10316                        selection.goal = SelectionGoal::None;
10317                    }
10318                })
10319            });
10320            this.insert("", window, cx);
10321            this.refresh_edit_prediction(true, false, window, cx);
10322        });
10323    }
10324
10325    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10326        if self.mode.is_single_line() {
10327            cx.propagate();
10328            return;
10329        }
10330
10331        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10332        if self.move_to_prev_snippet_tabstop(window, cx) {
10333            return;
10334        }
10335        self.outdent(&Outdent, window, cx);
10336    }
10337
10338    pub fn next_snippet_tabstop(
10339        &mut self,
10340        _: &NextSnippetTabstop,
10341        window: &mut Window,
10342        cx: &mut Context<Self>,
10343    ) {
10344        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10345            cx.propagate();
10346            return;
10347        }
10348
10349        if self.move_to_next_snippet_tabstop(window, cx) {
10350            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10351            return;
10352        }
10353        cx.propagate();
10354    }
10355
10356    pub fn previous_snippet_tabstop(
10357        &mut self,
10358        _: &PreviousSnippetTabstop,
10359        window: &mut Window,
10360        cx: &mut Context<Self>,
10361    ) {
10362        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10363            cx.propagate();
10364            return;
10365        }
10366
10367        if self.move_to_prev_snippet_tabstop(window, cx) {
10368            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10369            return;
10370        }
10371        cx.propagate();
10372    }
10373
10374    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10375        if self.mode.is_single_line() {
10376            cx.propagate();
10377            return;
10378        }
10379
10380        if self.move_to_next_snippet_tabstop(window, cx) {
10381            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10382            return;
10383        }
10384        if self.read_only(cx) {
10385            return;
10386        }
10387        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10388        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10389        let buffer = self.buffer.read(cx);
10390        let snapshot = buffer.snapshot(cx);
10391        let rows_iter = selections.iter().map(|s| s.head().row);
10392        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10393
10394        let has_some_cursor_in_whitespace = selections
10395            .iter()
10396            .filter(|selection| selection.is_empty())
10397            .any(|selection| {
10398                let cursor = selection.head();
10399                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10400                cursor.column < current_indent.len
10401            });
10402
10403        let mut edits = Vec::new();
10404        let mut prev_edited_row = 0;
10405        let mut row_delta = 0;
10406        for selection in &mut selections {
10407            if selection.start.row != prev_edited_row {
10408                row_delta = 0;
10409            }
10410            prev_edited_row = selection.end.row;
10411
10412            // If the selection is non-empty, then increase the indentation of the selected lines.
10413            if !selection.is_empty() {
10414                row_delta =
10415                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10416                continue;
10417            }
10418
10419            let cursor = selection.head();
10420            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10421            if let Some(suggested_indent) =
10422                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10423            {
10424                // Don't do anything if already at suggested indent
10425                // and there is any other cursor which is not
10426                if has_some_cursor_in_whitespace
10427                    && cursor.column == current_indent.len
10428                    && current_indent.len == suggested_indent.len
10429                {
10430                    continue;
10431                }
10432
10433                // Adjust line and move cursor to suggested indent
10434                // if cursor is not at suggested indent
10435                if cursor.column < suggested_indent.len
10436                    && cursor.column <= current_indent.len
10437                    && current_indent.len <= suggested_indent.len
10438                {
10439                    selection.start = Point::new(cursor.row, suggested_indent.len);
10440                    selection.end = selection.start;
10441                    if row_delta == 0 {
10442                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10443                            cursor.row,
10444                            current_indent,
10445                            suggested_indent,
10446                        ));
10447                        row_delta = suggested_indent.len - current_indent.len;
10448                    }
10449                    continue;
10450                }
10451
10452                // If current indent is more than suggested indent
10453                // only move cursor to current indent and skip indent
10454                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10455                    selection.start = Point::new(cursor.row, current_indent.len);
10456                    selection.end = selection.start;
10457                    continue;
10458                }
10459            }
10460
10461            // Otherwise, insert a hard or soft tab.
10462            let settings = buffer.language_settings_at(cursor, cx);
10463            let tab_size = if settings.hard_tabs {
10464                IndentSize::tab()
10465            } else {
10466                let tab_size = settings.tab_size.get();
10467                let indent_remainder = snapshot
10468                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10469                    .flat_map(str::chars)
10470                    .fold(row_delta % tab_size, |counter: u32, c| {
10471                        if c == '\t' {
10472                            0
10473                        } else {
10474                            (counter + 1) % tab_size
10475                        }
10476                    });
10477
10478                let chars_to_next_tab_stop = tab_size - indent_remainder;
10479                IndentSize::spaces(chars_to_next_tab_stop)
10480            };
10481            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10482            selection.end = selection.start;
10483            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10484            row_delta += tab_size.len;
10485        }
10486
10487        self.transact(window, cx, |this, window, cx| {
10488            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10489            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10490            this.refresh_edit_prediction(true, false, window, cx);
10491        });
10492    }
10493
10494    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10495        if self.read_only(cx) {
10496            return;
10497        }
10498        if self.mode.is_single_line() {
10499            cx.propagate();
10500            return;
10501        }
10502
10503        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10504        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10505        let mut prev_edited_row = 0;
10506        let mut row_delta = 0;
10507        let mut edits = Vec::new();
10508        let buffer = self.buffer.read(cx);
10509        let snapshot = buffer.snapshot(cx);
10510        for selection in &mut selections {
10511            if selection.start.row != prev_edited_row {
10512                row_delta = 0;
10513            }
10514            prev_edited_row = selection.end.row;
10515
10516            row_delta =
10517                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10518        }
10519
10520        self.transact(window, cx, |this, window, cx| {
10521            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10522            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10523        });
10524    }
10525
10526    fn indent_selection(
10527        buffer: &MultiBuffer,
10528        snapshot: &MultiBufferSnapshot,
10529        selection: &mut Selection<Point>,
10530        edits: &mut Vec<(Range<Point>, String)>,
10531        delta_for_start_row: u32,
10532        cx: &App,
10533    ) -> u32 {
10534        let settings = buffer.language_settings_at(selection.start, cx);
10535        let tab_size = settings.tab_size.get();
10536        let indent_kind = if settings.hard_tabs {
10537            IndentKind::Tab
10538        } else {
10539            IndentKind::Space
10540        };
10541        let mut start_row = selection.start.row;
10542        let mut end_row = selection.end.row + 1;
10543
10544        // If a selection ends at the beginning of a line, don't indent
10545        // that last line.
10546        if selection.end.column == 0 && selection.end.row > selection.start.row {
10547            end_row -= 1;
10548        }
10549
10550        // Avoid re-indenting a row that has already been indented by a
10551        // previous selection, but still update this selection's column
10552        // to reflect that indentation.
10553        if delta_for_start_row > 0 {
10554            start_row += 1;
10555            selection.start.column += delta_for_start_row;
10556            if selection.end.row == selection.start.row {
10557                selection.end.column += delta_for_start_row;
10558            }
10559        }
10560
10561        let mut delta_for_end_row = 0;
10562        let has_multiple_rows = start_row + 1 != end_row;
10563        for row in start_row..end_row {
10564            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10565            let indent_delta = match (current_indent.kind, indent_kind) {
10566                (IndentKind::Space, IndentKind::Space) => {
10567                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10568                    IndentSize::spaces(columns_to_next_tab_stop)
10569                }
10570                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10571                (_, IndentKind::Tab) => IndentSize::tab(),
10572            };
10573
10574            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10575                0
10576            } else {
10577                selection.start.column
10578            };
10579            let row_start = Point::new(row, start);
10580            edits.push((
10581                row_start..row_start,
10582                indent_delta.chars().collect::<String>(),
10583            ));
10584
10585            // Update this selection's endpoints to reflect the indentation.
10586            if row == selection.start.row {
10587                selection.start.column += indent_delta.len;
10588            }
10589            if row == selection.end.row {
10590                selection.end.column += indent_delta.len;
10591                delta_for_end_row = indent_delta.len;
10592            }
10593        }
10594
10595        if selection.start.row == selection.end.row {
10596            delta_for_start_row + delta_for_end_row
10597        } else {
10598            delta_for_end_row
10599        }
10600    }
10601
10602    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10603        if self.read_only(cx) {
10604            return;
10605        }
10606        if self.mode.is_single_line() {
10607            cx.propagate();
10608            return;
10609        }
10610
10611        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10612        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10613        let selections = self.selections.all::<Point>(&display_map);
10614        let mut deletion_ranges = Vec::new();
10615        let mut last_outdent = None;
10616        {
10617            let buffer = self.buffer.read(cx);
10618            let snapshot = buffer.snapshot(cx);
10619            for selection in &selections {
10620                let settings = buffer.language_settings_at(selection.start, cx);
10621                let tab_size = settings.tab_size.get();
10622                let mut rows = selection.spanned_rows(false, &display_map);
10623
10624                // Avoid re-outdenting a row that has already been outdented by a
10625                // previous selection.
10626                if let Some(last_row) = last_outdent
10627                    && last_row == rows.start
10628                {
10629                    rows.start = rows.start.next_row();
10630                }
10631                let has_multiple_rows = rows.len() > 1;
10632                for row in rows.iter_rows() {
10633                    let indent_size = snapshot.indent_size_for_line(row);
10634                    if indent_size.len > 0 {
10635                        let deletion_len = match indent_size.kind {
10636                            IndentKind::Space => {
10637                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10638                                if columns_to_prev_tab_stop == 0 {
10639                                    tab_size
10640                                } else {
10641                                    columns_to_prev_tab_stop
10642                                }
10643                            }
10644                            IndentKind::Tab => 1,
10645                        };
10646                        let start = if has_multiple_rows
10647                            || deletion_len > selection.start.column
10648                            || indent_size.len < selection.start.column
10649                        {
10650                            0
10651                        } else {
10652                            selection.start.column - deletion_len
10653                        };
10654                        deletion_ranges.push(
10655                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10656                        );
10657                        last_outdent = Some(row);
10658                    }
10659                }
10660            }
10661        }
10662
10663        self.transact(window, cx, |this, window, cx| {
10664            this.buffer.update(cx, |buffer, cx| {
10665                let empty_str: Arc<str> = Arc::default();
10666                buffer.edit(
10667                    deletion_ranges
10668                        .into_iter()
10669                        .map(|range| (range, empty_str.clone())),
10670                    None,
10671                    cx,
10672                );
10673            });
10674            let selections = this
10675                .selections
10676                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10677            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10678        });
10679    }
10680
10681    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10682        if self.read_only(cx) {
10683            return;
10684        }
10685        if self.mode.is_single_line() {
10686            cx.propagate();
10687            return;
10688        }
10689
10690        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10691        let selections = self
10692            .selections
10693            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10694            .into_iter()
10695            .map(|s| s.range());
10696
10697        self.transact(window, cx, |this, window, cx| {
10698            this.buffer.update(cx, |buffer, cx| {
10699                buffer.autoindent_ranges(selections, cx);
10700            });
10701            let selections = this
10702                .selections
10703                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10704            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10705        });
10706    }
10707
10708    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10709        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10710        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10711        let selections = self.selections.all::<Point>(&display_map);
10712
10713        let mut new_cursors = Vec::new();
10714        let mut edit_ranges = Vec::new();
10715        let mut selections = selections.iter().peekable();
10716        while let Some(selection) = selections.next() {
10717            let mut rows = selection.spanned_rows(false, &display_map);
10718
10719            // Accumulate contiguous regions of rows that we want to delete.
10720            while let Some(next_selection) = selections.peek() {
10721                let next_rows = next_selection.spanned_rows(false, &display_map);
10722                if next_rows.start <= rows.end {
10723                    rows.end = next_rows.end;
10724                    selections.next().unwrap();
10725                } else {
10726                    break;
10727                }
10728            }
10729
10730            let buffer = display_map.buffer_snapshot();
10731            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10732            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10733                // If there's a line after the range, delete the \n from the end of the row range
10734                (
10735                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10736                    rows.end,
10737                )
10738            } else {
10739                // If there isn't a line after the range, delete the \n from the line before the
10740                // start of the row range
10741                edit_start = edit_start.saturating_sub_usize(1);
10742                (buffer.len(), rows.start.previous_row())
10743            };
10744
10745            let text_layout_details = self.text_layout_details(window);
10746            let x = display_map.x_for_display_point(
10747                selection.head().to_display_point(&display_map),
10748                &text_layout_details,
10749            );
10750            let row = Point::new(target_row.0, 0)
10751                .to_display_point(&display_map)
10752                .row();
10753            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10754
10755            new_cursors.push((
10756                selection.id,
10757                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10758                SelectionGoal::None,
10759            ));
10760            edit_ranges.push(edit_start..edit_end);
10761        }
10762
10763        self.transact(window, cx, |this, window, cx| {
10764            let buffer = this.buffer.update(cx, |buffer, cx| {
10765                let empty_str: Arc<str> = Arc::default();
10766                buffer.edit(
10767                    edit_ranges
10768                        .into_iter()
10769                        .map(|range| (range, empty_str.clone())),
10770                    None,
10771                    cx,
10772                );
10773                buffer.snapshot(cx)
10774            });
10775            let new_selections = new_cursors
10776                .into_iter()
10777                .map(|(id, cursor, goal)| {
10778                    let cursor = cursor.to_point(&buffer);
10779                    Selection {
10780                        id,
10781                        start: cursor,
10782                        end: cursor,
10783                        reversed: false,
10784                        goal,
10785                    }
10786                })
10787                .collect();
10788
10789            this.change_selections(Default::default(), window, cx, |s| {
10790                s.select(new_selections);
10791            });
10792        });
10793    }
10794
10795    pub fn join_lines_impl(
10796        &mut self,
10797        insert_whitespace: bool,
10798        window: &mut Window,
10799        cx: &mut Context<Self>,
10800    ) {
10801        if self.read_only(cx) {
10802            return;
10803        }
10804        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10805        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10806            let start = MultiBufferRow(selection.start.row);
10807            // Treat single line selections as if they include the next line. Otherwise this action
10808            // would do nothing for single line selections individual cursors.
10809            let end = if selection.start.row == selection.end.row {
10810                MultiBufferRow(selection.start.row + 1)
10811            } else {
10812                MultiBufferRow(selection.end.row)
10813            };
10814
10815            if let Some(last_row_range) = row_ranges.last_mut()
10816                && start <= last_row_range.end
10817            {
10818                last_row_range.end = end;
10819                continue;
10820            }
10821            row_ranges.push(start..end);
10822        }
10823
10824        let snapshot = self.buffer.read(cx).snapshot(cx);
10825        let mut cursor_positions = Vec::new();
10826        for row_range in &row_ranges {
10827            let anchor = snapshot.anchor_before(Point::new(
10828                row_range.end.previous_row().0,
10829                snapshot.line_len(row_range.end.previous_row()),
10830            ));
10831            cursor_positions.push(anchor..anchor);
10832        }
10833
10834        self.transact(window, cx, |this, window, cx| {
10835            for row_range in row_ranges.into_iter().rev() {
10836                for row in row_range.iter_rows().rev() {
10837                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10838                    let next_line_row = row.next_row();
10839                    let indent = snapshot.indent_size_for_line(next_line_row);
10840                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10841
10842                    let replace =
10843                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10844                            " "
10845                        } else {
10846                            ""
10847                        };
10848
10849                    this.buffer.update(cx, |buffer, cx| {
10850                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10851                    });
10852                }
10853            }
10854
10855            this.change_selections(Default::default(), window, cx, |s| {
10856                s.select_anchor_ranges(cursor_positions)
10857            });
10858        });
10859    }
10860
10861    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10862        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10863        self.join_lines_impl(true, window, cx);
10864    }
10865
10866    pub fn sort_lines_case_sensitive(
10867        &mut self,
10868        _: &SortLinesCaseSensitive,
10869        window: &mut Window,
10870        cx: &mut Context<Self>,
10871    ) {
10872        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10873    }
10874
10875    pub fn sort_lines_by_length(
10876        &mut self,
10877        _: &SortLinesByLength,
10878        window: &mut Window,
10879        cx: &mut Context<Self>,
10880    ) {
10881        self.manipulate_immutable_lines(window, cx, |lines| {
10882            lines.sort_by_key(|&line| line.chars().count())
10883        })
10884    }
10885
10886    pub fn sort_lines_case_insensitive(
10887        &mut self,
10888        _: &SortLinesCaseInsensitive,
10889        window: &mut Window,
10890        cx: &mut Context<Self>,
10891    ) {
10892        self.manipulate_immutable_lines(window, cx, |lines| {
10893            lines.sort_by_key(|line| line.to_lowercase())
10894        })
10895    }
10896
10897    pub fn unique_lines_case_insensitive(
10898        &mut self,
10899        _: &UniqueLinesCaseInsensitive,
10900        window: &mut Window,
10901        cx: &mut Context<Self>,
10902    ) {
10903        self.manipulate_immutable_lines(window, cx, |lines| {
10904            let mut seen = HashSet::default();
10905            lines.retain(|line| seen.insert(line.to_lowercase()));
10906        })
10907    }
10908
10909    pub fn unique_lines_case_sensitive(
10910        &mut self,
10911        _: &UniqueLinesCaseSensitive,
10912        window: &mut Window,
10913        cx: &mut Context<Self>,
10914    ) {
10915        self.manipulate_immutable_lines(window, cx, |lines| {
10916            let mut seen = HashSet::default();
10917            lines.retain(|line| seen.insert(*line));
10918        })
10919    }
10920
10921    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10922        let snapshot = self.buffer.read(cx).snapshot(cx);
10923        for selection in self.selections.disjoint_anchors_arc().iter() {
10924            if snapshot
10925                .language_at(selection.start)
10926                .and_then(|lang| lang.config().wrap_characters.as_ref())
10927                .is_some()
10928            {
10929                return true;
10930            }
10931        }
10932        false
10933    }
10934
10935    fn wrap_selections_in_tag(
10936        &mut self,
10937        _: &WrapSelectionsInTag,
10938        window: &mut Window,
10939        cx: &mut Context<Self>,
10940    ) {
10941        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10942
10943        let snapshot = self.buffer.read(cx).snapshot(cx);
10944
10945        let mut edits = Vec::new();
10946        let mut boundaries = Vec::new();
10947
10948        for selection in self
10949            .selections
10950            .all_adjusted(&self.display_snapshot(cx))
10951            .iter()
10952        {
10953            let Some(wrap_config) = snapshot
10954                .language_at(selection.start)
10955                .and_then(|lang| lang.config().wrap_characters.clone())
10956            else {
10957                continue;
10958            };
10959
10960            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10961            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10962
10963            let start_before = snapshot.anchor_before(selection.start);
10964            let end_after = snapshot.anchor_after(selection.end);
10965
10966            edits.push((start_before..start_before, open_tag));
10967            edits.push((end_after..end_after, close_tag));
10968
10969            boundaries.push((
10970                start_before,
10971                end_after,
10972                wrap_config.start_prefix.len(),
10973                wrap_config.end_suffix.len(),
10974            ));
10975        }
10976
10977        if edits.is_empty() {
10978            return;
10979        }
10980
10981        self.transact(window, cx, |this, window, cx| {
10982            let buffer = this.buffer.update(cx, |buffer, cx| {
10983                buffer.edit(edits, None, cx);
10984                buffer.snapshot(cx)
10985            });
10986
10987            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10988            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10989                boundaries.into_iter()
10990            {
10991                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10992                let close_offset = end_after
10993                    .to_offset(&buffer)
10994                    .saturating_sub_usize(end_suffix_len);
10995                new_selections.push(open_offset..open_offset);
10996                new_selections.push(close_offset..close_offset);
10997            }
10998
10999            this.change_selections(Default::default(), window, cx, |s| {
11000                s.select_ranges(new_selections);
11001            });
11002
11003            this.request_autoscroll(Autoscroll::fit(), cx);
11004        });
11005    }
11006
11007    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11008        let Some(project) = self.project.clone() else {
11009            return;
11010        };
11011        self.reload(project, window, cx)
11012            .detach_and_notify_err(window, cx);
11013    }
11014
11015    pub fn restore_file(
11016        &mut self,
11017        _: &::git::RestoreFile,
11018        window: &mut Window,
11019        cx: &mut Context<Self>,
11020    ) {
11021        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11022        let mut buffer_ids = HashSet::default();
11023        let snapshot = self.buffer().read(cx).snapshot(cx);
11024        for selection in self
11025            .selections
11026            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11027        {
11028            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11029        }
11030
11031        let buffer = self.buffer().read(cx);
11032        let ranges = buffer_ids
11033            .into_iter()
11034            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11035            .collect::<Vec<_>>();
11036
11037        self.restore_hunks_in_ranges(ranges, window, cx);
11038    }
11039
11040    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11041        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11042        let selections = self
11043            .selections
11044            .all(&self.display_snapshot(cx))
11045            .into_iter()
11046            .map(|s| s.range())
11047            .collect();
11048        self.restore_hunks_in_ranges(selections, window, cx);
11049    }
11050
11051    pub fn restore_hunks_in_ranges(
11052        &mut self,
11053        ranges: Vec<Range<Point>>,
11054        window: &mut Window,
11055        cx: &mut Context<Editor>,
11056    ) {
11057        let mut revert_changes = HashMap::default();
11058        let chunk_by = self
11059            .snapshot(window, cx)
11060            .hunks_for_ranges(ranges)
11061            .into_iter()
11062            .chunk_by(|hunk| hunk.buffer_id);
11063        for (buffer_id, hunks) in &chunk_by {
11064            let hunks = hunks.collect::<Vec<_>>();
11065            for hunk in &hunks {
11066                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11067            }
11068            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11069        }
11070        drop(chunk_by);
11071        if !revert_changes.is_empty() {
11072            self.transact(window, cx, |editor, window, cx| {
11073                editor.restore(revert_changes, window, cx);
11074            });
11075        }
11076    }
11077
11078    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11079        if let Some(status) = self
11080            .addons
11081            .iter()
11082            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11083        {
11084            return Some(status);
11085        }
11086        self.project
11087            .as_ref()?
11088            .read(cx)
11089            .status_for_buffer_id(buffer_id, cx)
11090    }
11091
11092    pub fn open_active_item_in_terminal(
11093        &mut self,
11094        _: &OpenInTerminal,
11095        window: &mut Window,
11096        cx: &mut Context<Self>,
11097    ) {
11098        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11099            let project_path = buffer.read(cx).project_path(cx)?;
11100            let project = self.project()?.read(cx);
11101            let entry = project.entry_for_path(&project_path, cx)?;
11102            let parent = match &entry.canonical_path {
11103                Some(canonical_path) => canonical_path.to_path_buf(),
11104                None => project.absolute_path(&project_path, cx)?,
11105            }
11106            .parent()?
11107            .to_path_buf();
11108            Some(parent)
11109        }) {
11110            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11111        }
11112    }
11113
11114    fn set_breakpoint_context_menu(
11115        &mut self,
11116        display_row: DisplayRow,
11117        position: Option<Anchor>,
11118        clicked_point: gpui::Point<Pixels>,
11119        window: &mut Window,
11120        cx: &mut Context<Self>,
11121    ) {
11122        let source = self
11123            .buffer
11124            .read(cx)
11125            .snapshot(cx)
11126            .anchor_before(Point::new(display_row.0, 0u32));
11127
11128        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11129
11130        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11131            self,
11132            source,
11133            clicked_point,
11134            context_menu,
11135            window,
11136            cx,
11137        );
11138    }
11139
11140    fn add_edit_breakpoint_block(
11141        &mut self,
11142        anchor: Anchor,
11143        breakpoint: &Breakpoint,
11144        edit_action: BreakpointPromptEditAction,
11145        window: &mut Window,
11146        cx: &mut Context<Self>,
11147    ) {
11148        let weak_editor = cx.weak_entity();
11149        let bp_prompt = cx.new(|cx| {
11150            BreakpointPromptEditor::new(
11151                weak_editor,
11152                anchor,
11153                breakpoint.clone(),
11154                edit_action,
11155                window,
11156                cx,
11157            )
11158        });
11159
11160        let height = bp_prompt.update(cx, |this, cx| {
11161            this.prompt
11162                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11163        });
11164        let cloned_prompt = bp_prompt.clone();
11165        let blocks = vec![BlockProperties {
11166            style: BlockStyle::Sticky,
11167            placement: BlockPlacement::Above(anchor),
11168            height: Some(height),
11169            render: Arc::new(move |cx| {
11170                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11171                cloned_prompt.clone().into_any_element()
11172            }),
11173            priority: 0,
11174        }];
11175
11176        let focus_handle = bp_prompt.focus_handle(cx);
11177        window.focus(&focus_handle);
11178
11179        let block_ids = self.insert_blocks(blocks, None, cx);
11180        bp_prompt.update(cx, |prompt, _| {
11181            prompt.add_block_ids(block_ids);
11182        });
11183    }
11184
11185    pub(crate) fn breakpoint_at_row(
11186        &self,
11187        row: u32,
11188        window: &mut Window,
11189        cx: &mut Context<Self>,
11190    ) -> Option<(Anchor, Breakpoint)> {
11191        let snapshot = self.snapshot(window, cx);
11192        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11193
11194        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11195    }
11196
11197    pub(crate) fn breakpoint_at_anchor(
11198        &self,
11199        breakpoint_position: Anchor,
11200        snapshot: &EditorSnapshot,
11201        cx: &mut Context<Self>,
11202    ) -> Option<(Anchor, Breakpoint)> {
11203        let buffer = self
11204            .buffer
11205            .read(cx)
11206            .buffer_for_anchor(breakpoint_position, cx)?;
11207
11208        let enclosing_excerpt = breakpoint_position.excerpt_id;
11209        let buffer_snapshot = buffer.read(cx).snapshot();
11210
11211        let row = buffer_snapshot
11212            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11213            .row;
11214
11215        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11216        let anchor_end = snapshot
11217            .buffer_snapshot()
11218            .anchor_after(Point::new(row, line_len));
11219
11220        self.breakpoint_store
11221            .as_ref()?
11222            .read_with(cx, |breakpoint_store, cx| {
11223                breakpoint_store
11224                    .breakpoints(
11225                        &buffer,
11226                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11227                        &buffer_snapshot,
11228                        cx,
11229                    )
11230                    .next()
11231                    .and_then(|(bp, _)| {
11232                        let breakpoint_row = buffer_snapshot
11233                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11234                            .row;
11235
11236                        if breakpoint_row == row {
11237                            snapshot
11238                                .buffer_snapshot()
11239                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11240                                .map(|position| (position, bp.bp.clone()))
11241                        } else {
11242                            None
11243                        }
11244                    })
11245            })
11246    }
11247
11248    pub fn edit_log_breakpoint(
11249        &mut self,
11250        _: &EditLogBreakpoint,
11251        window: &mut Window,
11252        cx: &mut Context<Self>,
11253    ) {
11254        if self.breakpoint_store.is_none() {
11255            return;
11256        }
11257
11258        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11259            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11260                message: None,
11261                state: BreakpointState::Enabled,
11262                condition: None,
11263                hit_condition: None,
11264            });
11265
11266            self.add_edit_breakpoint_block(
11267                anchor,
11268                &breakpoint,
11269                BreakpointPromptEditAction::Log,
11270                window,
11271                cx,
11272            );
11273        }
11274    }
11275
11276    fn breakpoints_at_cursors(
11277        &self,
11278        window: &mut Window,
11279        cx: &mut Context<Self>,
11280    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11281        let snapshot = self.snapshot(window, cx);
11282        let cursors = self
11283            .selections
11284            .disjoint_anchors_arc()
11285            .iter()
11286            .map(|selection| {
11287                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11288
11289                let breakpoint_position = self
11290                    .breakpoint_at_row(cursor_position.row, window, cx)
11291                    .map(|bp| bp.0)
11292                    .unwrap_or_else(|| {
11293                        snapshot
11294                            .display_snapshot
11295                            .buffer_snapshot()
11296                            .anchor_after(Point::new(cursor_position.row, 0))
11297                    });
11298
11299                let breakpoint = self
11300                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11301                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11302
11303                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11304            })
11305            // 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.
11306            .collect::<HashMap<Anchor, _>>();
11307
11308        cursors.into_iter().collect()
11309    }
11310
11311    pub fn enable_breakpoint(
11312        &mut self,
11313        _: &crate::actions::EnableBreakpoint,
11314        window: &mut Window,
11315        cx: &mut Context<Self>,
11316    ) {
11317        if self.breakpoint_store.is_none() {
11318            return;
11319        }
11320
11321        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11322            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11323                continue;
11324            };
11325            self.edit_breakpoint_at_anchor(
11326                anchor,
11327                breakpoint,
11328                BreakpointEditAction::InvertState,
11329                cx,
11330            );
11331        }
11332    }
11333
11334    pub fn disable_breakpoint(
11335        &mut self,
11336        _: &crate::actions::DisableBreakpoint,
11337        window: &mut Window,
11338        cx: &mut Context<Self>,
11339    ) {
11340        if self.breakpoint_store.is_none() {
11341            return;
11342        }
11343
11344        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11345            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11346                continue;
11347            };
11348            self.edit_breakpoint_at_anchor(
11349                anchor,
11350                breakpoint,
11351                BreakpointEditAction::InvertState,
11352                cx,
11353            );
11354        }
11355    }
11356
11357    pub fn toggle_breakpoint(
11358        &mut self,
11359        _: &crate::actions::ToggleBreakpoint,
11360        window: &mut Window,
11361        cx: &mut Context<Self>,
11362    ) {
11363        if self.breakpoint_store.is_none() {
11364            return;
11365        }
11366
11367        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11368            if let Some(breakpoint) = breakpoint {
11369                self.edit_breakpoint_at_anchor(
11370                    anchor,
11371                    breakpoint,
11372                    BreakpointEditAction::Toggle,
11373                    cx,
11374                );
11375            } else {
11376                self.edit_breakpoint_at_anchor(
11377                    anchor,
11378                    Breakpoint::new_standard(),
11379                    BreakpointEditAction::Toggle,
11380                    cx,
11381                );
11382            }
11383        }
11384    }
11385
11386    pub fn edit_breakpoint_at_anchor(
11387        &mut self,
11388        breakpoint_position: Anchor,
11389        breakpoint: Breakpoint,
11390        edit_action: BreakpointEditAction,
11391        cx: &mut Context<Self>,
11392    ) {
11393        let Some(breakpoint_store) = &self.breakpoint_store else {
11394            return;
11395        };
11396
11397        let Some(buffer) = self
11398            .buffer
11399            .read(cx)
11400            .buffer_for_anchor(breakpoint_position, cx)
11401        else {
11402            return;
11403        };
11404
11405        breakpoint_store.update(cx, |breakpoint_store, cx| {
11406            breakpoint_store.toggle_breakpoint(
11407                buffer,
11408                BreakpointWithPosition {
11409                    position: breakpoint_position.text_anchor,
11410                    bp: breakpoint,
11411                },
11412                edit_action,
11413                cx,
11414            );
11415        });
11416
11417        cx.notify();
11418    }
11419
11420    #[cfg(any(test, feature = "test-support"))]
11421    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11422        self.breakpoint_store.clone()
11423    }
11424
11425    pub fn prepare_restore_change(
11426        &self,
11427        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11428        hunk: &MultiBufferDiffHunk,
11429        cx: &mut App,
11430    ) -> Option<()> {
11431        if hunk.is_created_file() {
11432            return None;
11433        }
11434        let buffer = self.buffer.read(cx);
11435        let diff = buffer.diff_for(hunk.buffer_id)?;
11436        let buffer = buffer.buffer(hunk.buffer_id)?;
11437        let buffer = buffer.read(cx);
11438        let original_text = diff
11439            .read(cx)
11440            .base_text()
11441            .as_rope()
11442            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11443        let buffer_snapshot = buffer.snapshot();
11444        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11445        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11446            probe
11447                .0
11448                .start
11449                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11450                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11451        }) {
11452            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11453            Some(())
11454        } else {
11455            None
11456        }
11457    }
11458
11459    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11460        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11461    }
11462
11463    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11464        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11465    }
11466
11467    fn manipulate_lines<M>(
11468        &mut self,
11469        window: &mut Window,
11470        cx: &mut Context<Self>,
11471        mut manipulate: M,
11472    ) where
11473        M: FnMut(&str) -> LineManipulationResult,
11474    {
11475        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11476
11477        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11478        let buffer = self.buffer.read(cx).snapshot(cx);
11479
11480        let mut edits = Vec::new();
11481
11482        let selections = self.selections.all::<Point>(&display_map);
11483        let mut selections = selections.iter().peekable();
11484        let mut contiguous_row_selections = Vec::new();
11485        let mut new_selections = Vec::new();
11486        let mut added_lines = 0;
11487        let mut removed_lines = 0;
11488
11489        while let Some(selection) = selections.next() {
11490            let (start_row, end_row) = consume_contiguous_rows(
11491                &mut contiguous_row_selections,
11492                selection,
11493                &display_map,
11494                &mut selections,
11495            );
11496
11497            let start_point = Point::new(start_row.0, 0);
11498            let end_point = Point::new(
11499                end_row.previous_row().0,
11500                buffer.line_len(end_row.previous_row()),
11501            );
11502            let text = buffer
11503                .text_for_range(start_point..end_point)
11504                .collect::<String>();
11505
11506            let LineManipulationResult {
11507                new_text,
11508                line_count_before,
11509                line_count_after,
11510            } = manipulate(&text);
11511
11512            edits.push((start_point..end_point, new_text));
11513
11514            // Selections must change based on added and removed line count
11515            let start_row =
11516                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11517            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11518            new_selections.push(Selection {
11519                id: selection.id,
11520                start: start_row,
11521                end: end_row,
11522                goal: SelectionGoal::None,
11523                reversed: selection.reversed,
11524            });
11525
11526            if line_count_after > line_count_before {
11527                added_lines += line_count_after - line_count_before;
11528            } else if line_count_before > line_count_after {
11529                removed_lines += line_count_before - line_count_after;
11530            }
11531        }
11532
11533        self.transact(window, cx, |this, window, cx| {
11534            let buffer = this.buffer.update(cx, |buffer, cx| {
11535                buffer.edit(edits, None, cx);
11536                buffer.snapshot(cx)
11537            });
11538
11539            // Recalculate offsets on newly edited buffer
11540            let new_selections = new_selections
11541                .iter()
11542                .map(|s| {
11543                    let start_point = Point::new(s.start.0, 0);
11544                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11545                    Selection {
11546                        id: s.id,
11547                        start: buffer.point_to_offset(start_point),
11548                        end: buffer.point_to_offset(end_point),
11549                        goal: s.goal,
11550                        reversed: s.reversed,
11551                    }
11552                })
11553                .collect();
11554
11555            this.change_selections(Default::default(), window, cx, |s| {
11556                s.select(new_selections);
11557            });
11558
11559            this.request_autoscroll(Autoscroll::fit(), cx);
11560        });
11561    }
11562
11563    fn manipulate_immutable_lines<Fn>(
11564        &mut self,
11565        window: &mut Window,
11566        cx: &mut Context<Self>,
11567        mut callback: Fn,
11568    ) where
11569        Fn: FnMut(&mut Vec<&str>),
11570    {
11571        self.manipulate_lines(window, cx, |text| {
11572            let mut lines: Vec<&str> = text.split('\n').collect();
11573            let line_count_before = lines.len();
11574
11575            callback(&mut lines);
11576
11577            LineManipulationResult {
11578                new_text: lines.join("\n"),
11579                line_count_before,
11580                line_count_after: lines.len(),
11581            }
11582        });
11583    }
11584
11585    fn manipulate_mutable_lines<Fn>(
11586        &mut self,
11587        window: &mut Window,
11588        cx: &mut Context<Self>,
11589        mut callback: Fn,
11590    ) where
11591        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11592    {
11593        self.manipulate_lines(window, cx, |text| {
11594            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11595            let line_count_before = lines.len();
11596
11597            callback(&mut lines);
11598
11599            LineManipulationResult {
11600                new_text: lines.join("\n"),
11601                line_count_before,
11602                line_count_after: lines.len(),
11603            }
11604        });
11605    }
11606
11607    pub fn convert_indentation_to_spaces(
11608        &mut self,
11609        _: &ConvertIndentationToSpaces,
11610        window: &mut Window,
11611        cx: &mut Context<Self>,
11612    ) {
11613        let settings = self.buffer.read(cx).language_settings(cx);
11614        let tab_size = settings.tab_size.get() as usize;
11615
11616        self.manipulate_mutable_lines(window, cx, |lines| {
11617            // Allocates a reasonably sized scratch buffer once for the whole loop
11618            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11619            // Avoids recomputing spaces that could be inserted many times
11620            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11621                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11622                .collect();
11623
11624            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11625                let mut chars = line.as_ref().chars();
11626                let mut col = 0;
11627                let mut changed = false;
11628
11629                for ch in chars.by_ref() {
11630                    match ch {
11631                        ' ' => {
11632                            reindented_line.push(' ');
11633                            col += 1;
11634                        }
11635                        '\t' => {
11636                            // \t are converted to spaces depending on the current column
11637                            let spaces_len = tab_size - (col % tab_size);
11638                            reindented_line.extend(&space_cache[spaces_len - 1]);
11639                            col += spaces_len;
11640                            changed = true;
11641                        }
11642                        _ => {
11643                            // If we dont append before break, the character is consumed
11644                            reindented_line.push(ch);
11645                            break;
11646                        }
11647                    }
11648                }
11649
11650                if !changed {
11651                    reindented_line.clear();
11652                    continue;
11653                }
11654                // Append the rest of the line and replace old reference with new one
11655                reindented_line.extend(chars);
11656                *line = Cow::Owned(reindented_line.clone());
11657                reindented_line.clear();
11658            }
11659        });
11660    }
11661
11662    pub fn convert_indentation_to_tabs(
11663        &mut self,
11664        _: &ConvertIndentationToTabs,
11665        window: &mut Window,
11666        cx: &mut Context<Self>,
11667    ) {
11668        let settings = self.buffer.read(cx).language_settings(cx);
11669        let tab_size = settings.tab_size.get() as usize;
11670
11671        self.manipulate_mutable_lines(window, cx, |lines| {
11672            // Allocates a reasonably sized buffer once for the whole loop
11673            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11674            // Avoids recomputing spaces that could be inserted many times
11675            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11676                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11677                .collect();
11678
11679            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11680                let mut chars = line.chars();
11681                let mut spaces_count = 0;
11682                let mut first_non_indent_char = None;
11683                let mut changed = false;
11684
11685                for ch in chars.by_ref() {
11686                    match ch {
11687                        ' ' => {
11688                            // Keep track of spaces. Append \t when we reach tab_size
11689                            spaces_count += 1;
11690                            changed = true;
11691                            if spaces_count == tab_size {
11692                                reindented_line.push('\t');
11693                                spaces_count = 0;
11694                            }
11695                        }
11696                        '\t' => {
11697                            reindented_line.push('\t');
11698                            spaces_count = 0;
11699                        }
11700                        _ => {
11701                            // Dont append it yet, we might have remaining spaces
11702                            first_non_indent_char = Some(ch);
11703                            break;
11704                        }
11705                    }
11706                }
11707
11708                if !changed {
11709                    reindented_line.clear();
11710                    continue;
11711                }
11712                // Remaining spaces that didn't make a full tab stop
11713                if spaces_count > 0 {
11714                    reindented_line.extend(&space_cache[spaces_count - 1]);
11715                }
11716                // If we consume an extra character that was not indentation, add it back
11717                if let Some(extra_char) = first_non_indent_char {
11718                    reindented_line.push(extra_char);
11719                }
11720                // Append the rest of the line and replace old reference with new one
11721                reindented_line.extend(chars);
11722                *line = Cow::Owned(reindented_line.clone());
11723                reindented_line.clear();
11724            }
11725        });
11726    }
11727
11728    pub fn convert_to_upper_case(
11729        &mut self,
11730        _: &ConvertToUpperCase,
11731        window: &mut Window,
11732        cx: &mut Context<Self>,
11733    ) {
11734        self.manipulate_text(window, cx, |text| text.to_uppercase())
11735    }
11736
11737    pub fn convert_to_lower_case(
11738        &mut self,
11739        _: &ConvertToLowerCase,
11740        window: &mut Window,
11741        cx: &mut Context<Self>,
11742    ) {
11743        self.manipulate_text(window, cx, |text| text.to_lowercase())
11744    }
11745
11746    pub fn convert_to_title_case(
11747        &mut self,
11748        _: &ConvertToTitleCase,
11749        window: &mut Window,
11750        cx: &mut Context<Self>,
11751    ) {
11752        self.manipulate_text(window, cx, |text| {
11753            text.split('\n')
11754                .map(|line| line.to_case(Case::Title))
11755                .join("\n")
11756        })
11757    }
11758
11759    pub fn convert_to_snake_case(
11760        &mut self,
11761        _: &ConvertToSnakeCase,
11762        window: &mut Window,
11763        cx: &mut Context<Self>,
11764    ) {
11765        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11766    }
11767
11768    pub fn convert_to_kebab_case(
11769        &mut self,
11770        _: &ConvertToKebabCase,
11771        window: &mut Window,
11772        cx: &mut Context<Self>,
11773    ) {
11774        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11775    }
11776
11777    pub fn convert_to_upper_camel_case(
11778        &mut self,
11779        _: &ConvertToUpperCamelCase,
11780        window: &mut Window,
11781        cx: &mut Context<Self>,
11782    ) {
11783        self.manipulate_text(window, cx, |text| {
11784            text.split('\n')
11785                .map(|line| line.to_case(Case::UpperCamel))
11786                .join("\n")
11787        })
11788    }
11789
11790    pub fn convert_to_lower_camel_case(
11791        &mut self,
11792        _: &ConvertToLowerCamelCase,
11793        window: &mut Window,
11794        cx: &mut Context<Self>,
11795    ) {
11796        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11797    }
11798
11799    pub fn convert_to_opposite_case(
11800        &mut self,
11801        _: &ConvertToOppositeCase,
11802        window: &mut Window,
11803        cx: &mut Context<Self>,
11804    ) {
11805        self.manipulate_text(window, cx, |text| {
11806            text.chars()
11807                .fold(String::with_capacity(text.len()), |mut t, c| {
11808                    if c.is_uppercase() {
11809                        t.extend(c.to_lowercase());
11810                    } else {
11811                        t.extend(c.to_uppercase());
11812                    }
11813                    t
11814                })
11815        })
11816    }
11817
11818    pub fn convert_to_sentence_case(
11819        &mut self,
11820        _: &ConvertToSentenceCase,
11821        window: &mut Window,
11822        cx: &mut Context<Self>,
11823    ) {
11824        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11825    }
11826
11827    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11828        self.manipulate_text(window, cx, |text| {
11829            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11830            if has_upper_case_characters {
11831                text.to_lowercase()
11832            } else {
11833                text.to_uppercase()
11834            }
11835        })
11836    }
11837
11838    pub fn convert_to_rot13(
11839        &mut self,
11840        _: &ConvertToRot13,
11841        window: &mut Window,
11842        cx: &mut Context<Self>,
11843    ) {
11844        self.manipulate_text(window, cx, |text| {
11845            text.chars()
11846                .map(|c| match c {
11847                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11848                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11849                    _ => c,
11850                })
11851                .collect()
11852        })
11853    }
11854
11855    pub fn convert_to_rot47(
11856        &mut self,
11857        _: &ConvertToRot47,
11858        window: &mut Window,
11859        cx: &mut Context<Self>,
11860    ) {
11861        self.manipulate_text(window, cx, |text| {
11862            text.chars()
11863                .map(|c| {
11864                    let code_point = c as u32;
11865                    if code_point >= 33 && code_point <= 126 {
11866                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11867                    }
11868                    c
11869                })
11870                .collect()
11871        })
11872    }
11873
11874    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11875    where
11876        Fn: FnMut(&str) -> String,
11877    {
11878        let buffer = self.buffer.read(cx).snapshot(cx);
11879
11880        let mut new_selections = Vec::new();
11881        let mut edits = Vec::new();
11882        let mut selection_adjustment = 0isize;
11883
11884        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11885            let selection_is_empty = selection.is_empty();
11886
11887            let (start, end) = if selection_is_empty {
11888                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11889                (word_range.start, word_range.end)
11890            } else {
11891                (
11892                    buffer.point_to_offset(selection.start),
11893                    buffer.point_to_offset(selection.end),
11894                )
11895            };
11896
11897            let text = buffer.text_for_range(start..end).collect::<String>();
11898            let old_length = text.len() as isize;
11899            let text = callback(&text);
11900
11901            new_selections.push(Selection {
11902                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
11903                end: MultiBufferOffset(
11904                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
11905                ),
11906                goal: SelectionGoal::None,
11907                id: selection.id,
11908                reversed: selection.reversed,
11909            });
11910
11911            selection_adjustment += old_length - text.len() as isize;
11912
11913            edits.push((start..end, text));
11914        }
11915
11916        self.transact(window, cx, |this, window, cx| {
11917            this.buffer.update(cx, |buffer, cx| {
11918                buffer.edit(edits, None, cx);
11919            });
11920
11921            this.change_selections(Default::default(), window, cx, |s| {
11922                s.select(new_selections);
11923            });
11924
11925            this.request_autoscroll(Autoscroll::fit(), cx);
11926        });
11927    }
11928
11929    pub fn move_selection_on_drop(
11930        &mut self,
11931        selection: &Selection<Anchor>,
11932        target: DisplayPoint,
11933        is_cut: bool,
11934        window: &mut Window,
11935        cx: &mut Context<Self>,
11936    ) {
11937        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11938        let buffer = display_map.buffer_snapshot();
11939        let mut edits = Vec::new();
11940        let insert_point = display_map
11941            .clip_point(target, Bias::Left)
11942            .to_point(&display_map);
11943        let text = buffer
11944            .text_for_range(selection.start..selection.end)
11945            .collect::<String>();
11946        if is_cut {
11947            edits.push(((selection.start..selection.end), String::new()));
11948        }
11949        let insert_anchor = buffer.anchor_before(insert_point);
11950        edits.push(((insert_anchor..insert_anchor), text));
11951        let last_edit_start = insert_anchor.bias_left(buffer);
11952        let last_edit_end = insert_anchor.bias_right(buffer);
11953        self.transact(window, cx, |this, window, cx| {
11954            this.buffer.update(cx, |buffer, cx| {
11955                buffer.edit(edits, None, cx);
11956            });
11957            this.change_selections(Default::default(), window, cx, |s| {
11958                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11959            });
11960        });
11961    }
11962
11963    pub fn clear_selection_drag_state(&mut self) {
11964        self.selection_drag_state = SelectionDragState::None;
11965    }
11966
11967    pub fn duplicate(
11968        &mut self,
11969        upwards: bool,
11970        whole_lines: bool,
11971        window: &mut Window,
11972        cx: &mut Context<Self>,
11973    ) {
11974        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11975
11976        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11977        let buffer = display_map.buffer_snapshot();
11978        let selections = self.selections.all::<Point>(&display_map);
11979
11980        let mut edits = Vec::new();
11981        let mut selections_iter = selections.iter().peekable();
11982        while let Some(selection) = selections_iter.next() {
11983            let mut rows = selection.spanned_rows(false, &display_map);
11984            // duplicate line-wise
11985            if whole_lines || selection.start == selection.end {
11986                // Avoid duplicating the same lines twice.
11987                while let Some(next_selection) = selections_iter.peek() {
11988                    let next_rows = next_selection.spanned_rows(false, &display_map);
11989                    if next_rows.start < rows.end {
11990                        rows.end = next_rows.end;
11991                        selections_iter.next().unwrap();
11992                    } else {
11993                        break;
11994                    }
11995                }
11996
11997                // Copy the text from the selected row region and splice it either at the start
11998                // or end of the region.
11999                let start = Point::new(rows.start.0, 0);
12000                let end = Point::new(
12001                    rows.end.previous_row().0,
12002                    buffer.line_len(rows.end.previous_row()),
12003                );
12004
12005                let mut text = buffer.text_for_range(start..end).collect::<String>();
12006
12007                let insert_location = if upwards {
12008                    // When duplicating upward, we need to insert before the current line.
12009                    // If we're on the last line and it doesn't end with a newline,
12010                    // we need to add a newline before the duplicated content.
12011                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12012                        && buffer.max_point().column > 0
12013                        && !text.ends_with('\n');
12014
12015                    if needs_leading_newline {
12016                        text.insert(0, '\n');
12017                        end
12018                    } else {
12019                        text.push('\n');
12020                        Point::new(rows.start.0, 0)
12021                    }
12022                } else {
12023                    text.push('\n');
12024                    start
12025                };
12026                edits.push((insert_location..insert_location, text));
12027            } else {
12028                // duplicate character-wise
12029                let start = selection.start;
12030                let end = selection.end;
12031                let text = buffer.text_for_range(start..end).collect::<String>();
12032                edits.push((selection.end..selection.end, text));
12033            }
12034        }
12035
12036        self.transact(window, cx, |this, window, cx| {
12037            this.buffer.update(cx, |buffer, cx| {
12038                buffer.edit(edits, None, cx);
12039            });
12040
12041            // When duplicating upward with whole lines, move the cursor to the duplicated line
12042            if upwards && whole_lines {
12043                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12044
12045                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12046                    let mut new_ranges = Vec::new();
12047                    let selections = s.all::<Point>(&display_map);
12048                    let mut selections_iter = selections.iter().peekable();
12049
12050                    while let Some(first_selection) = selections_iter.next() {
12051                        // Group contiguous selections together to find the total row span
12052                        let mut group_selections = vec![first_selection];
12053                        let mut rows = first_selection.spanned_rows(false, &display_map);
12054
12055                        while let Some(next_selection) = selections_iter.peek() {
12056                            let next_rows = next_selection.spanned_rows(false, &display_map);
12057                            if next_rows.start < rows.end {
12058                                rows.end = next_rows.end;
12059                                group_selections.push(selections_iter.next().unwrap());
12060                            } else {
12061                                break;
12062                            }
12063                        }
12064
12065                        let row_count = rows.end.0 - rows.start.0;
12066
12067                        // Move all selections in this group up by the total number of duplicated rows
12068                        for selection in group_selections {
12069                            let new_start = Point::new(
12070                                selection.start.row.saturating_sub(row_count),
12071                                selection.start.column,
12072                            );
12073
12074                            let new_end = Point::new(
12075                                selection.end.row.saturating_sub(row_count),
12076                                selection.end.column,
12077                            );
12078
12079                            new_ranges.push(new_start..new_end);
12080                        }
12081                    }
12082
12083                    s.select_ranges(new_ranges);
12084                });
12085            }
12086
12087            this.request_autoscroll(Autoscroll::fit(), cx);
12088        });
12089    }
12090
12091    pub fn duplicate_line_up(
12092        &mut self,
12093        _: &DuplicateLineUp,
12094        window: &mut Window,
12095        cx: &mut Context<Self>,
12096    ) {
12097        self.duplicate(true, true, window, cx);
12098    }
12099
12100    pub fn duplicate_line_down(
12101        &mut self,
12102        _: &DuplicateLineDown,
12103        window: &mut Window,
12104        cx: &mut Context<Self>,
12105    ) {
12106        self.duplicate(false, true, window, cx);
12107    }
12108
12109    pub fn duplicate_selection(
12110        &mut self,
12111        _: &DuplicateSelection,
12112        window: &mut Window,
12113        cx: &mut Context<Self>,
12114    ) {
12115        self.duplicate(false, false, window, cx);
12116    }
12117
12118    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12119        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12120        if self.mode.is_single_line() {
12121            cx.propagate();
12122            return;
12123        }
12124
12125        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12126        let buffer = self.buffer.read(cx).snapshot(cx);
12127
12128        let mut edits = Vec::new();
12129        let mut unfold_ranges = Vec::new();
12130        let mut refold_creases = Vec::new();
12131
12132        let selections = self.selections.all::<Point>(&display_map);
12133        let mut selections = selections.iter().peekable();
12134        let mut contiguous_row_selections = Vec::new();
12135        let mut new_selections = Vec::new();
12136
12137        while let Some(selection) = selections.next() {
12138            // Find all the selections that span a contiguous row range
12139            let (start_row, end_row) = consume_contiguous_rows(
12140                &mut contiguous_row_selections,
12141                selection,
12142                &display_map,
12143                &mut selections,
12144            );
12145
12146            // Move the text spanned by the row range to be before the line preceding the row range
12147            if start_row.0 > 0 {
12148                let range_to_move = Point::new(
12149                    start_row.previous_row().0,
12150                    buffer.line_len(start_row.previous_row()),
12151                )
12152                    ..Point::new(
12153                        end_row.previous_row().0,
12154                        buffer.line_len(end_row.previous_row()),
12155                    );
12156                let insertion_point = display_map
12157                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12158                    .0;
12159
12160                // Don't move lines across excerpts
12161                if buffer
12162                    .excerpt_containing(insertion_point..range_to_move.end)
12163                    .is_some()
12164                {
12165                    let text = buffer
12166                        .text_for_range(range_to_move.clone())
12167                        .flat_map(|s| s.chars())
12168                        .skip(1)
12169                        .chain(['\n'])
12170                        .collect::<String>();
12171
12172                    edits.push((
12173                        buffer.anchor_after(range_to_move.start)
12174                            ..buffer.anchor_before(range_to_move.end),
12175                        String::new(),
12176                    ));
12177                    let insertion_anchor = buffer.anchor_after(insertion_point);
12178                    edits.push((insertion_anchor..insertion_anchor, text));
12179
12180                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12181
12182                    // Move selections up
12183                    new_selections.extend(contiguous_row_selections.drain(..).map(
12184                        |mut selection| {
12185                            selection.start.row -= row_delta;
12186                            selection.end.row -= row_delta;
12187                            selection
12188                        },
12189                    ));
12190
12191                    // Move folds up
12192                    unfold_ranges.push(range_to_move.clone());
12193                    for fold in display_map.folds_in_range(
12194                        buffer.anchor_before(range_to_move.start)
12195                            ..buffer.anchor_after(range_to_move.end),
12196                    ) {
12197                        let mut start = fold.range.start.to_point(&buffer);
12198                        let mut end = fold.range.end.to_point(&buffer);
12199                        start.row -= row_delta;
12200                        end.row -= row_delta;
12201                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12202                    }
12203                }
12204            }
12205
12206            // If we didn't move line(s), preserve the existing selections
12207            new_selections.append(&mut contiguous_row_selections);
12208        }
12209
12210        self.transact(window, cx, |this, window, cx| {
12211            this.unfold_ranges(&unfold_ranges, true, true, cx);
12212            this.buffer.update(cx, |buffer, cx| {
12213                for (range, text) in edits {
12214                    buffer.edit([(range, text)], None, cx);
12215                }
12216            });
12217            this.fold_creases(refold_creases, true, window, cx);
12218            this.change_selections(Default::default(), window, cx, |s| {
12219                s.select(new_selections);
12220            })
12221        });
12222    }
12223
12224    pub fn move_line_down(
12225        &mut self,
12226        _: &MoveLineDown,
12227        window: &mut Window,
12228        cx: &mut Context<Self>,
12229    ) {
12230        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12231        if self.mode.is_single_line() {
12232            cx.propagate();
12233            return;
12234        }
12235
12236        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12237        let buffer = self.buffer.read(cx).snapshot(cx);
12238
12239        let mut edits = Vec::new();
12240        let mut unfold_ranges = Vec::new();
12241        let mut refold_creases = Vec::new();
12242
12243        let selections = self.selections.all::<Point>(&display_map);
12244        let mut selections = selections.iter().peekable();
12245        let mut contiguous_row_selections = Vec::new();
12246        let mut new_selections = Vec::new();
12247
12248        while let Some(selection) = selections.next() {
12249            // Find all the selections that span a contiguous row range
12250            let (start_row, end_row) = consume_contiguous_rows(
12251                &mut contiguous_row_selections,
12252                selection,
12253                &display_map,
12254                &mut selections,
12255            );
12256
12257            // Move the text spanned by the row range to be after the last line of the row range
12258            if end_row.0 <= buffer.max_point().row {
12259                let range_to_move =
12260                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12261                let insertion_point = display_map
12262                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12263                    .0;
12264
12265                // Don't move lines across excerpt boundaries
12266                if buffer
12267                    .excerpt_containing(range_to_move.start..insertion_point)
12268                    .is_some()
12269                {
12270                    let mut text = String::from("\n");
12271                    text.extend(buffer.text_for_range(range_to_move.clone()));
12272                    text.pop(); // Drop trailing newline
12273                    edits.push((
12274                        buffer.anchor_after(range_to_move.start)
12275                            ..buffer.anchor_before(range_to_move.end),
12276                        String::new(),
12277                    ));
12278                    let insertion_anchor = buffer.anchor_after(insertion_point);
12279                    edits.push((insertion_anchor..insertion_anchor, text));
12280
12281                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12282
12283                    // Move selections down
12284                    new_selections.extend(contiguous_row_selections.drain(..).map(
12285                        |mut selection| {
12286                            selection.start.row += row_delta;
12287                            selection.end.row += row_delta;
12288                            selection
12289                        },
12290                    ));
12291
12292                    // Move folds down
12293                    unfold_ranges.push(range_to_move.clone());
12294                    for fold in display_map.folds_in_range(
12295                        buffer.anchor_before(range_to_move.start)
12296                            ..buffer.anchor_after(range_to_move.end),
12297                    ) {
12298                        let mut start = fold.range.start.to_point(&buffer);
12299                        let mut end = fold.range.end.to_point(&buffer);
12300                        start.row += row_delta;
12301                        end.row += row_delta;
12302                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12303                    }
12304                }
12305            }
12306
12307            // If we didn't move line(s), preserve the existing selections
12308            new_selections.append(&mut contiguous_row_selections);
12309        }
12310
12311        self.transact(window, cx, |this, window, cx| {
12312            this.unfold_ranges(&unfold_ranges, true, true, cx);
12313            this.buffer.update(cx, |buffer, cx| {
12314                for (range, text) in edits {
12315                    buffer.edit([(range, text)], None, cx);
12316                }
12317            });
12318            this.fold_creases(refold_creases, true, window, cx);
12319            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12320        });
12321    }
12322
12323    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12324        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12325        let text_layout_details = &self.text_layout_details(window);
12326        self.transact(window, cx, |this, window, cx| {
12327            let edits = this.change_selections(Default::default(), window, cx, |s| {
12328                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12329                s.move_with(|display_map, selection| {
12330                    if !selection.is_empty() {
12331                        return;
12332                    }
12333
12334                    let mut head = selection.head();
12335                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12336                    if head.column() == display_map.line_len(head.row()) {
12337                        transpose_offset = display_map
12338                            .buffer_snapshot()
12339                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12340                    }
12341
12342                    if transpose_offset == MultiBufferOffset(0) {
12343                        return;
12344                    }
12345
12346                    *head.column_mut() += 1;
12347                    head = display_map.clip_point(head, Bias::Right);
12348                    let goal = SelectionGoal::HorizontalPosition(
12349                        display_map
12350                            .x_for_display_point(head, text_layout_details)
12351                            .into(),
12352                    );
12353                    selection.collapse_to(head, goal);
12354
12355                    let transpose_start = display_map
12356                        .buffer_snapshot()
12357                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12358                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12359                        let transpose_end = display_map
12360                            .buffer_snapshot()
12361                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12362                        if let Some(ch) = display_map
12363                            .buffer_snapshot()
12364                            .chars_at(transpose_start)
12365                            .next()
12366                        {
12367                            edits.push((transpose_start..transpose_offset, String::new()));
12368                            edits.push((transpose_end..transpose_end, ch.to_string()));
12369                        }
12370                    }
12371                });
12372                edits
12373            });
12374            this.buffer
12375                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12376            let selections = this
12377                .selections
12378                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12379            this.change_selections(Default::default(), window, cx, |s| {
12380                s.select(selections);
12381            });
12382        });
12383    }
12384
12385    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12386        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12387        if self.mode.is_single_line() {
12388            cx.propagate();
12389            return;
12390        }
12391
12392        self.rewrap_impl(RewrapOptions::default(), cx)
12393    }
12394
12395    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12396        let buffer = self.buffer.read(cx).snapshot(cx);
12397        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12398
12399        #[derive(Clone, Debug, PartialEq)]
12400        enum CommentFormat {
12401            /// single line comment, with prefix for line
12402            Line(String),
12403            /// single line within a block comment, with prefix for line
12404            BlockLine(String),
12405            /// a single line of a block comment that includes the initial delimiter
12406            BlockCommentWithStart(BlockCommentConfig),
12407            /// a single line of a block comment that includes the ending delimiter
12408            BlockCommentWithEnd(BlockCommentConfig),
12409        }
12410
12411        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12412        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12413            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12414                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12415                .peekable();
12416
12417            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12418                row
12419            } else {
12420                return Vec::new();
12421            };
12422
12423            let language_settings = buffer.language_settings_at(selection.head(), cx);
12424            let language_scope = buffer.language_scope_at(selection.head());
12425
12426            let indent_and_prefix_for_row =
12427                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12428                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12429                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12430                        &language_scope
12431                    {
12432                        let indent_end = Point::new(row, indent.len);
12433                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12434                        let line_text_after_indent = buffer
12435                            .text_for_range(indent_end..line_end)
12436                            .collect::<String>();
12437
12438                        let is_within_comment_override = buffer
12439                            .language_scope_at(indent_end)
12440                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12441                        let comment_delimiters = if is_within_comment_override {
12442                            // we are within a comment syntax node, but we don't
12443                            // yet know what kind of comment: block, doc or line
12444                            match (
12445                                language_scope.documentation_comment(),
12446                                language_scope.block_comment(),
12447                            ) {
12448                                (Some(config), _) | (_, Some(config))
12449                                    if buffer.contains_str_at(indent_end, &config.start) =>
12450                                {
12451                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12452                                }
12453                                (Some(config), _) | (_, Some(config))
12454                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12455                                {
12456                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12457                                }
12458                                (Some(config), _) | (_, Some(config))
12459                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12460                                {
12461                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12462                                }
12463                                (_, _) => language_scope
12464                                    .line_comment_prefixes()
12465                                    .iter()
12466                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12467                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12468                            }
12469                        } else {
12470                            // we not in an overridden comment node, but we may
12471                            // be within a non-overridden line comment node
12472                            language_scope
12473                                .line_comment_prefixes()
12474                                .iter()
12475                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12476                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12477                        };
12478
12479                        let rewrap_prefix = language_scope
12480                            .rewrap_prefixes()
12481                            .iter()
12482                            .find_map(|prefix_regex| {
12483                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12484                                    if mat.start() == 0 {
12485                                        Some(mat.as_str().to_string())
12486                                    } else {
12487                                        None
12488                                    }
12489                                })
12490                            })
12491                            .flatten();
12492                        (comment_delimiters, rewrap_prefix)
12493                    } else {
12494                        (None, None)
12495                    };
12496                    (indent, comment_prefix, rewrap_prefix)
12497                };
12498
12499            let mut ranges = Vec::new();
12500            let from_empty_selection = selection.is_empty();
12501
12502            let mut current_range_start = first_row;
12503            let mut prev_row = first_row;
12504            let (
12505                mut current_range_indent,
12506                mut current_range_comment_delimiters,
12507                mut current_range_rewrap_prefix,
12508            ) = indent_and_prefix_for_row(first_row);
12509
12510            for row in non_blank_rows_iter.skip(1) {
12511                let has_paragraph_break = row > prev_row + 1;
12512
12513                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12514                    indent_and_prefix_for_row(row);
12515
12516                let has_indent_change = row_indent != current_range_indent;
12517                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12518
12519                let has_boundary_change = has_comment_change
12520                    || row_rewrap_prefix.is_some()
12521                    || (has_indent_change && current_range_comment_delimiters.is_some());
12522
12523                if has_paragraph_break || has_boundary_change {
12524                    ranges.push((
12525                        language_settings.clone(),
12526                        Point::new(current_range_start, 0)
12527                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12528                        current_range_indent,
12529                        current_range_comment_delimiters.clone(),
12530                        current_range_rewrap_prefix.clone(),
12531                        from_empty_selection,
12532                    ));
12533                    current_range_start = row;
12534                    current_range_indent = row_indent;
12535                    current_range_comment_delimiters = row_comment_delimiters;
12536                    current_range_rewrap_prefix = row_rewrap_prefix;
12537                }
12538                prev_row = row;
12539            }
12540
12541            ranges.push((
12542                language_settings.clone(),
12543                Point::new(current_range_start, 0)
12544                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12545                current_range_indent,
12546                current_range_comment_delimiters,
12547                current_range_rewrap_prefix,
12548                from_empty_selection,
12549            ));
12550
12551            ranges
12552        });
12553
12554        let mut edits = Vec::new();
12555        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12556
12557        for (
12558            language_settings,
12559            wrap_range,
12560            mut indent_size,
12561            comment_prefix,
12562            rewrap_prefix,
12563            from_empty_selection,
12564        ) in wrap_ranges
12565        {
12566            let mut start_row = wrap_range.start.row;
12567            let mut end_row = wrap_range.end.row;
12568
12569            // Skip selections that overlap with a range that has already been rewrapped.
12570            let selection_range = start_row..end_row;
12571            if rewrapped_row_ranges
12572                .iter()
12573                .any(|range| range.overlaps(&selection_range))
12574            {
12575                continue;
12576            }
12577
12578            let tab_size = language_settings.tab_size;
12579
12580            let (line_prefix, inside_comment) = match &comment_prefix {
12581                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12582                    (Some(prefix.as_str()), true)
12583                }
12584                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12585                    (Some(prefix.as_ref()), true)
12586                }
12587                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12588                    start: _,
12589                    end: _,
12590                    prefix,
12591                    tab_size,
12592                })) => {
12593                    indent_size.len += tab_size;
12594                    (Some(prefix.as_ref()), true)
12595                }
12596                None => (None, false),
12597            };
12598            let indent_prefix = indent_size.chars().collect::<String>();
12599            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12600
12601            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12602                RewrapBehavior::InComments => inside_comment,
12603                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12604                RewrapBehavior::Anywhere => true,
12605            };
12606
12607            let should_rewrap = options.override_language_settings
12608                || allow_rewrap_based_on_language
12609                || self.hard_wrap.is_some();
12610            if !should_rewrap {
12611                continue;
12612            }
12613
12614            if from_empty_selection {
12615                'expand_upwards: while start_row > 0 {
12616                    let prev_row = start_row - 1;
12617                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12618                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12619                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12620                    {
12621                        start_row = prev_row;
12622                    } else {
12623                        break 'expand_upwards;
12624                    }
12625                }
12626
12627                'expand_downwards: while end_row < buffer.max_point().row {
12628                    let next_row = end_row + 1;
12629                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12630                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12631                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12632                    {
12633                        end_row = next_row;
12634                    } else {
12635                        break 'expand_downwards;
12636                    }
12637                }
12638            }
12639
12640            let start = Point::new(start_row, 0);
12641            let start_offset = ToOffset::to_offset(&start, &buffer);
12642            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12643            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12644            let mut first_line_delimiter = None;
12645            let mut last_line_delimiter = None;
12646            let Some(lines_without_prefixes) = selection_text
12647                .lines()
12648                .enumerate()
12649                .map(|(ix, line)| {
12650                    let line_trimmed = line.trim_start();
12651                    if rewrap_prefix.is_some() && ix > 0 {
12652                        Ok(line_trimmed)
12653                    } else if let Some(
12654                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12655                            start,
12656                            prefix,
12657                            end,
12658                            tab_size,
12659                        })
12660                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12661                            start,
12662                            prefix,
12663                            end,
12664                            tab_size,
12665                        }),
12666                    ) = &comment_prefix
12667                    {
12668                        let line_trimmed = line_trimmed
12669                            .strip_prefix(start.as_ref())
12670                            .map(|s| {
12671                                let mut indent_size = indent_size;
12672                                indent_size.len -= tab_size;
12673                                let indent_prefix: String = indent_size.chars().collect();
12674                                first_line_delimiter = Some((indent_prefix, start));
12675                                s.trim_start()
12676                            })
12677                            .unwrap_or(line_trimmed);
12678                        let line_trimmed = line_trimmed
12679                            .strip_suffix(end.as_ref())
12680                            .map(|s| {
12681                                last_line_delimiter = Some(end);
12682                                s.trim_end()
12683                            })
12684                            .unwrap_or(line_trimmed);
12685                        let line_trimmed = line_trimmed
12686                            .strip_prefix(prefix.as_ref())
12687                            .unwrap_or(line_trimmed);
12688                        Ok(line_trimmed)
12689                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12690                        line_trimmed.strip_prefix(prefix).with_context(|| {
12691                            format!("line did not start with prefix {prefix:?}: {line:?}")
12692                        })
12693                    } else {
12694                        line_trimmed
12695                            .strip_prefix(&line_prefix.trim_start())
12696                            .with_context(|| {
12697                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12698                            })
12699                    }
12700                })
12701                .collect::<Result<Vec<_>, _>>()
12702                .log_err()
12703            else {
12704                continue;
12705            };
12706
12707            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12708                buffer
12709                    .language_settings_at(Point::new(start_row, 0), cx)
12710                    .preferred_line_length as usize
12711            });
12712
12713            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12714                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12715            } else {
12716                line_prefix.clone()
12717            };
12718
12719            let wrapped_text = {
12720                let mut wrapped_text = wrap_with_prefix(
12721                    line_prefix,
12722                    subsequent_lines_prefix,
12723                    lines_without_prefixes.join("\n"),
12724                    wrap_column,
12725                    tab_size,
12726                    options.preserve_existing_whitespace,
12727                );
12728
12729                if let Some((indent, delimiter)) = first_line_delimiter {
12730                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12731                }
12732                if let Some(last_line) = last_line_delimiter {
12733                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12734                }
12735
12736                wrapped_text
12737            };
12738
12739            // TODO: should always use char-based diff while still supporting cursor behavior that
12740            // matches vim.
12741            let mut diff_options = DiffOptions::default();
12742            if options.override_language_settings {
12743                diff_options.max_word_diff_len = 0;
12744                diff_options.max_word_diff_line_count = 0;
12745            } else {
12746                diff_options.max_word_diff_len = usize::MAX;
12747                diff_options.max_word_diff_line_count = usize::MAX;
12748            }
12749
12750            for (old_range, new_text) in
12751                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12752            {
12753                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12754                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12755                edits.push((edit_start..edit_end, new_text));
12756            }
12757
12758            rewrapped_row_ranges.push(start_row..=end_row);
12759        }
12760
12761        self.buffer
12762            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12763    }
12764
12765    pub fn cut_common(
12766        &mut self,
12767        cut_no_selection_line: bool,
12768        window: &mut Window,
12769        cx: &mut Context<Self>,
12770    ) -> ClipboardItem {
12771        let mut text = String::new();
12772        let buffer = self.buffer.read(cx).snapshot(cx);
12773        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12774        let mut clipboard_selections = Vec::with_capacity(selections.len());
12775        {
12776            let max_point = buffer.max_point();
12777            let mut is_first = true;
12778            let mut prev_selection_was_entire_line = false;
12779            for selection in &mut selections {
12780                let is_entire_line =
12781                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12782                if is_entire_line {
12783                    selection.start = Point::new(selection.start.row, 0);
12784                    if !selection.is_empty() && selection.end.column == 0 {
12785                        selection.end = cmp::min(max_point, selection.end);
12786                    } else {
12787                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12788                    }
12789                    selection.goal = SelectionGoal::None;
12790                }
12791                if is_first {
12792                    is_first = false;
12793                } else if !prev_selection_was_entire_line {
12794                    text += "\n";
12795                }
12796                prev_selection_was_entire_line = is_entire_line;
12797                let mut len = 0;
12798                for chunk in buffer.text_for_range(selection.start..selection.end) {
12799                    text.push_str(chunk);
12800                    len += chunk.len();
12801                }
12802                clipboard_selections.push(ClipboardSelection {
12803                    len,
12804                    is_entire_line,
12805                    first_line_indent: buffer
12806                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12807                        .len,
12808                });
12809            }
12810        }
12811
12812        self.transact(window, cx, |this, window, cx| {
12813            this.change_selections(Default::default(), window, cx, |s| {
12814                s.select(selections);
12815            });
12816            this.insert("", window, cx);
12817        });
12818        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12819    }
12820
12821    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12822        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12823        let item = self.cut_common(true, window, cx);
12824        cx.write_to_clipboard(item);
12825    }
12826
12827    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12828        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12829        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12830            s.move_with(|snapshot, sel| {
12831                if sel.is_empty() {
12832                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12833                }
12834                if sel.is_empty() {
12835                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12836                }
12837            });
12838        });
12839        let item = self.cut_common(false, window, cx);
12840        cx.set_global(KillRing(item))
12841    }
12842
12843    pub fn kill_ring_yank(
12844        &mut self,
12845        _: &KillRingYank,
12846        window: &mut Window,
12847        cx: &mut Context<Self>,
12848    ) {
12849        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12850        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12851            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12852                (kill_ring.text().to_string(), kill_ring.metadata_json())
12853            } else {
12854                return;
12855            }
12856        } else {
12857            return;
12858        };
12859        self.do_paste(&text, metadata, false, window, cx);
12860    }
12861
12862    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12863        self.do_copy(true, cx);
12864    }
12865
12866    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12867        self.do_copy(false, cx);
12868    }
12869
12870    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12871        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12872        let buffer = self.buffer.read(cx).read(cx);
12873        let mut text = String::new();
12874
12875        let mut clipboard_selections = Vec::with_capacity(selections.len());
12876        {
12877            let max_point = buffer.max_point();
12878            let mut is_first = true;
12879            let mut prev_selection_was_entire_line = false;
12880            for selection in &selections {
12881                let mut start = selection.start;
12882                let mut end = selection.end;
12883                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12884                let mut add_trailing_newline = false;
12885                if is_entire_line {
12886                    start = Point::new(start.row, 0);
12887                    let next_line_start = Point::new(end.row + 1, 0);
12888                    if next_line_start <= max_point {
12889                        end = next_line_start;
12890                    } else {
12891                        // We're on the last line without a trailing newline.
12892                        // Copy to the end of the line and add a newline afterwards.
12893                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12894                        add_trailing_newline = true;
12895                    }
12896                }
12897
12898                let mut trimmed_selections = Vec::new();
12899                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12900                    let row = MultiBufferRow(start.row);
12901                    let first_indent = buffer.indent_size_for_line(row);
12902                    if first_indent.len == 0 || start.column > first_indent.len {
12903                        trimmed_selections.push(start..end);
12904                    } else {
12905                        trimmed_selections.push(
12906                            Point::new(row.0, first_indent.len)
12907                                ..Point::new(row.0, buffer.line_len(row)),
12908                        );
12909                        for row in start.row + 1..=end.row {
12910                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12911                            if row == end.row {
12912                                line_len = end.column;
12913                            }
12914                            if line_len == 0 {
12915                                trimmed_selections
12916                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12917                                continue;
12918                            }
12919                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12920                            if row_indent_size.len >= first_indent.len {
12921                                trimmed_selections.push(
12922                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12923                                );
12924                            } else {
12925                                trimmed_selections.clear();
12926                                trimmed_selections.push(start..end);
12927                                break;
12928                            }
12929                        }
12930                    }
12931                } else {
12932                    trimmed_selections.push(start..end);
12933                }
12934
12935                for trimmed_range in trimmed_selections {
12936                    if is_first {
12937                        is_first = false;
12938                    } else if !prev_selection_was_entire_line {
12939                        text += "\n";
12940                    }
12941                    prev_selection_was_entire_line = is_entire_line;
12942                    let mut len = 0;
12943                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12944                        text.push_str(chunk);
12945                        len += chunk.len();
12946                    }
12947                    if add_trailing_newline {
12948                        text.push('\n');
12949                        len += 1;
12950                    }
12951                    clipboard_selections.push(ClipboardSelection {
12952                        len,
12953                        is_entire_line,
12954                        first_line_indent: buffer
12955                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12956                            .len,
12957                    });
12958                }
12959            }
12960        }
12961
12962        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12963            text,
12964            clipboard_selections,
12965        ));
12966    }
12967
12968    pub fn do_paste(
12969        &mut self,
12970        text: &String,
12971        clipboard_selections: Option<Vec<ClipboardSelection>>,
12972        handle_entire_lines: bool,
12973        window: &mut Window,
12974        cx: &mut Context<Self>,
12975    ) {
12976        if self.read_only(cx) {
12977            return;
12978        }
12979
12980        let clipboard_text = Cow::Borrowed(text.as_str());
12981
12982        self.transact(window, cx, |this, window, cx| {
12983            let had_active_edit_prediction = this.has_active_edit_prediction();
12984            let display_map = this.display_snapshot(cx);
12985            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
12986            let cursor_offset = this
12987                .selections
12988                .last::<MultiBufferOffset>(&display_map)
12989                .head();
12990
12991            if let Some(mut clipboard_selections) = clipboard_selections {
12992                let all_selections_were_entire_line =
12993                    clipboard_selections.iter().all(|s| s.is_entire_line);
12994                let first_selection_indent_column =
12995                    clipboard_selections.first().map(|s| s.first_line_indent);
12996                if clipboard_selections.len() != old_selections.len() {
12997                    clipboard_selections.drain(..);
12998                }
12999                let mut auto_indent_on_paste = true;
13000
13001                this.buffer.update(cx, |buffer, cx| {
13002                    let snapshot = buffer.read(cx);
13003                    auto_indent_on_paste = snapshot
13004                        .language_settings_at(cursor_offset, cx)
13005                        .auto_indent_on_paste;
13006
13007                    let mut start_offset = 0;
13008                    let mut edits = Vec::new();
13009                    let mut original_indent_columns = Vec::new();
13010                    for (ix, selection) in old_selections.iter().enumerate() {
13011                        let to_insert;
13012                        let entire_line;
13013                        let original_indent_column;
13014                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13015                            let end_offset = start_offset + clipboard_selection.len;
13016                            to_insert = &clipboard_text[start_offset..end_offset];
13017                            entire_line = clipboard_selection.is_entire_line;
13018                            start_offset = if entire_line {
13019                                end_offset
13020                            } else {
13021                                end_offset + 1
13022                            };
13023                            original_indent_column = Some(clipboard_selection.first_line_indent);
13024                        } else {
13025                            to_insert = &*clipboard_text;
13026                            entire_line = all_selections_were_entire_line;
13027                            original_indent_column = first_selection_indent_column
13028                        }
13029
13030                        let (range, to_insert) =
13031                            if selection.is_empty() && handle_entire_lines && entire_line {
13032                                // If the corresponding selection was empty when this slice of the
13033                                // clipboard text was written, then the entire line containing the
13034                                // selection was copied. If this selection is also currently empty,
13035                                // then paste the line before the current line of the buffer.
13036                                let column = selection.start.to_point(&snapshot).column as usize;
13037                                let line_start = selection.start - column;
13038                                (line_start..line_start, Cow::Borrowed(to_insert))
13039                            } else {
13040                                let language = snapshot.language_at(selection.head());
13041                                let range = selection.range();
13042                                if let Some(language) = language
13043                                    && language.name() == "Markdown".into()
13044                                {
13045                                    edit_for_markdown_paste(
13046                                        &snapshot,
13047                                        range,
13048                                        to_insert,
13049                                        url::Url::parse(to_insert).ok(),
13050                                    )
13051                                } else {
13052                                    (range, Cow::Borrowed(to_insert))
13053                                }
13054                            };
13055
13056                        edits.push((range, to_insert));
13057                        original_indent_columns.push(original_indent_column);
13058                    }
13059                    drop(snapshot);
13060
13061                    buffer.edit(
13062                        edits,
13063                        if auto_indent_on_paste {
13064                            Some(AutoindentMode::Block {
13065                                original_indent_columns,
13066                            })
13067                        } else {
13068                            None
13069                        },
13070                        cx,
13071                    );
13072                });
13073
13074                let selections = this
13075                    .selections
13076                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13077                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13078            } else {
13079                let url = url::Url::parse(&clipboard_text).ok();
13080
13081                let auto_indent_mode = if !clipboard_text.is_empty() {
13082                    Some(AutoindentMode::Block {
13083                        original_indent_columns: Vec::new(),
13084                    })
13085                } else {
13086                    None
13087                };
13088
13089                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13090                    let snapshot = buffer.snapshot(cx);
13091
13092                    let anchors = old_selections
13093                        .iter()
13094                        .map(|s| {
13095                            let anchor = snapshot.anchor_after(s.head());
13096                            s.map(|_| anchor)
13097                        })
13098                        .collect::<Vec<_>>();
13099
13100                    let mut edits = Vec::new();
13101
13102                    for selection in old_selections.iter() {
13103                        let language = snapshot.language_at(selection.head());
13104                        let range = selection.range();
13105
13106                        let (edit_range, edit_text) = if let Some(language) = language
13107                            && language.name() == "Markdown".into()
13108                        {
13109                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13110                        } else {
13111                            (range, clipboard_text.clone())
13112                        };
13113
13114                        edits.push((edit_range, edit_text));
13115                    }
13116
13117                    drop(snapshot);
13118                    buffer.edit(edits, auto_indent_mode, cx);
13119
13120                    anchors
13121                });
13122
13123                this.change_selections(Default::default(), window, cx, |s| {
13124                    s.select_anchors(selection_anchors);
13125                });
13126            }
13127
13128            //   🤔                 |    ..     | show_in_menu |
13129            // | ..                  |   true        true
13130            // | had_edit_prediction |   false       true
13131
13132            let trigger_in_words =
13133                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13134
13135            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13136        });
13137    }
13138
13139    pub fn diff_clipboard_with_selection(
13140        &mut self,
13141        _: &DiffClipboardWithSelection,
13142        window: &mut Window,
13143        cx: &mut Context<Self>,
13144    ) {
13145        let selections = self
13146            .selections
13147            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13148
13149        if selections.is_empty() {
13150            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13151            return;
13152        };
13153
13154        let clipboard_text = match cx.read_from_clipboard() {
13155            Some(item) => match item.entries().first() {
13156                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13157                _ => None,
13158            },
13159            None => None,
13160        };
13161
13162        let Some(clipboard_text) = clipboard_text else {
13163            log::warn!("Clipboard doesn't contain text.");
13164            return;
13165        };
13166
13167        window.dispatch_action(
13168            Box::new(DiffClipboardWithSelectionData {
13169                clipboard_text,
13170                editor: cx.entity(),
13171            }),
13172            cx,
13173        );
13174    }
13175
13176    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13177        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13178        if let Some(item) = cx.read_from_clipboard() {
13179            let entries = item.entries();
13180
13181            match entries.first() {
13182                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13183                // of all the pasted entries.
13184                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13185                    .do_paste(
13186                        clipboard_string.text(),
13187                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13188                        true,
13189                        window,
13190                        cx,
13191                    ),
13192                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13193            }
13194        }
13195    }
13196
13197    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13198        if self.read_only(cx) {
13199            return;
13200        }
13201
13202        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13203
13204        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13205            if let Some((selections, _)) =
13206                self.selection_history.transaction(transaction_id).cloned()
13207            {
13208                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13209                    s.select_anchors(selections.to_vec());
13210                });
13211            } else {
13212                log::error!(
13213                    "No entry in selection_history found for undo. \
13214                     This may correspond to a bug where undo does not update the selection. \
13215                     If this is occurring, please add details to \
13216                     https://github.com/zed-industries/zed/issues/22692"
13217                );
13218            }
13219            self.request_autoscroll(Autoscroll::fit(), cx);
13220            self.unmark_text(window, cx);
13221            self.refresh_edit_prediction(true, false, window, cx);
13222            cx.emit(EditorEvent::Edited { transaction_id });
13223            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13224        }
13225    }
13226
13227    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13228        if self.read_only(cx) {
13229            return;
13230        }
13231
13232        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13233
13234        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13235            if let Some((_, Some(selections))) =
13236                self.selection_history.transaction(transaction_id).cloned()
13237            {
13238                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13239                    s.select_anchors(selections.to_vec());
13240                });
13241            } else {
13242                log::error!(
13243                    "No entry in selection_history found for redo. \
13244                     This may correspond to a bug where undo does not update the selection. \
13245                     If this is occurring, please add details to \
13246                     https://github.com/zed-industries/zed/issues/22692"
13247                );
13248            }
13249            self.request_autoscroll(Autoscroll::fit(), cx);
13250            self.unmark_text(window, cx);
13251            self.refresh_edit_prediction(true, false, window, cx);
13252            cx.emit(EditorEvent::Edited { transaction_id });
13253        }
13254    }
13255
13256    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13257        self.buffer
13258            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13259    }
13260
13261    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13262        self.buffer
13263            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13264    }
13265
13266    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13267        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13268        self.change_selections(Default::default(), window, cx, |s| {
13269            s.move_with(|map, selection| {
13270                let cursor = if selection.is_empty() {
13271                    movement::left(map, selection.start)
13272                } else {
13273                    selection.start
13274                };
13275                selection.collapse_to(cursor, SelectionGoal::None);
13276            });
13277        })
13278    }
13279
13280    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13281        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13282        self.change_selections(Default::default(), window, cx, |s| {
13283            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13284        })
13285    }
13286
13287    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13288        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13289        self.change_selections(Default::default(), window, cx, |s| {
13290            s.move_with(|map, selection| {
13291                let cursor = if selection.is_empty() {
13292                    movement::right(map, selection.end)
13293                } else {
13294                    selection.end
13295                };
13296                selection.collapse_to(cursor, SelectionGoal::None)
13297            });
13298        })
13299    }
13300
13301    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13302        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13303        self.change_selections(Default::default(), window, cx, |s| {
13304            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13305        });
13306    }
13307
13308    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13309        if self.take_rename(true, window, cx).is_some() {
13310            return;
13311        }
13312
13313        if self.mode.is_single_line() {
13314            cx.propagate();
13315            return;
13316        }
13317
13318        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13319
13320        let text_layout_details = &self.text_layout_details(window);
13321        let selection_count = self.selections.count();
13322        let first_selection = self.selections.first_anchor();
13323
13324        self.change_selections(Default::default(), window, cx, |s| {
13325            s.move_with(|map, selection| {
13326                if !selection.is_empty() {
13327                    selection.goal = SelectionGoal::None;
13328                }
13329                let (cursor, goal) = movement::up(
13330                    map,
13331                    selection.start,
13332                    selection.goal,
13333                    false,
13334                    text_layout_details,
13335                );
13336                selection.collapse_to(cursor, goal);
13337            });
13338        });
13339
13340        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13341        {
13342            cx.propagate();
13343        }
13344    }
13345
13346    pub fn move_up_by_lines(
13347        &mut self,
13348        action: &MoveUpByLines,
13349        window: &mut Window,
13350        cx: &mut Context<Self>,
13351    ) {
13352        if self.take_rename(true, window, cx).is_some() {
13353            return;
13354        }
13355
13356        if self.mode.is_single_line() {
13357            cx.propagate();
13358            return;
13359        }
13360
13361        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13362
13363        let text_layout_details = &self.text_layout_details(window);
13364
13365        self.change_selections(Default::default(), window, cx, |s| {
13366            s.move_with(|map, selection| {
13367                if !selection.is_empty() {
13368                    selection.goal = SelectionGoal::None;
13369                }
13370                let (cursor, goal) = movement::up_by_rows(
13371                    map,
13372                    selection.start,
13373                    action.lines,
13374                    selection.goal,
13375                    false,
13376                    text_layout_details,
13377                );
13378                selection.collapse_to(cursor, goal);
13379            });
13380        })
13381    }
13382
13383    pub fn move_down_by_lines(
13384        &mut self,
13385        action: &MoveDownByLines,
13386        window: &mut Window,
13387        cx: &mut Context<Self>,
13388    ) {
13389        if self.take_rename(true, window, cx).is_some() {
13390            return;
13391        }
13392
13393        if self.mode.is_single_line() {
13394            cx.propagate();
13395            return;
13396        }
13397
13398        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13399
13400        let text_layout_details = &self.text_layout_details(window);
13401
13402        self.change_selections(Default::default(), window, cx, |s| {
13403            s.move_with(|map, selection| {
13404                if !selection.is_empty() {
13405                    selection.goal = SelectionGoal::None;
13406                }
13407                let (cursor, goal) = movement::down_by_rows(
13408                    map,
13409                    selection.start,
13410                    action.lines,
13411                    selection.goal,
13412                    false,
13413                    text_layout_details,
13414                );
13415                selection.collapse_to(cursor, goal);
13416            });
13417        })
13418    }
13419
13420    pub fn select_down_by_lines(
13421        &mut self,
13422        action: &SelectDownByLines,
13423        window: &mut Window,
13424        cx: &mut Context<Self>,
13425    ) {
13426        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13427        let text_layout_details = &self.text_layout_details(window);
13428        self.change_selections(Default::default(), window, cx, |s| {
13429            s.move_heads_with(|map, head, goal| {
13430                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13431            })
13432        })
13433    }
13434
13435    pub fn select_up_by_lines(
13436        &mut self,
13437        action: &SelectUpByLines,
13438        window: &mut Window,
13439        cx: &mut Context<Self>,
13440    ) {
13441        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13442        let text_layout_details = &self.text_layout_details(window);
13443        self.change_selections(Default::default(), window, cx, |s| {
13444            s.move_heads_with(|map, head, goal| {
13445                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13446            })
13447        })
13448    }
13449
13450    pub fn select_page_up(
13451        &mut self,
13452        _: &SelectPageUp,
13453        window: &mut Window,
13454        cx: &mut Context<Self>,
13455    ) {
13456        let Some(row_count) = self.visible_row_count() else {
13457            return;
13458        };
13459
13460        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13461
13462        let text_layout_details = &self.text_layout_details(window);
13463
13464        self.change_selections(Default::default(), window, cx, |s| {
13465            s.move_heads_with(|map, head, goal| {
13466                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13467            })
13468        })
13469    }
13470
13471    pub fn move_page_up(
13472        &mut self,
13473        action: &MovePageUp,
13474        window: &mut Window,
13475        cx: &mut Context<Self>,
13476    ) {
13477        if self.take_rename(true, window, cx).is_some() {
13478            return;
13479        }
13480
13481        if self
13482            .context_menu
13483            .borrow_mut()
13484            .as_mut()
13485            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13486            .unwrap_or(false)
13487        {
13488            return;
13489        }
13490
13491        if matches!(self.mode, EditorMode::SingleLine) {
13492            cx.propagate();
13493            return;
13494        }
13495
13496        let Some(row_count) = self.visible_row_count() else {
13497            return;
13498        };
13499
13500        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13501
13502        let effects = if action.center_cursor {
13503            SelectionEffects::scroll(Autoscroll::center())
13504        } else {
13505            SelectionEffects::default()
13506        };
13507
13508        let text_layout_details = &self.text_layout_details(window);
13509
13510        self.change_selections(effects, window, cx, |s| {
13511            s.move_with(|map, selection| {
13512                if !selection.is_empty() {
13513                    selection.goal = SelectionGoal::None;
13514                }
13515                let (cursor, goal) = movement::up_by_rows(
13516                    map,
13517                    selection.end,
13518                    row_count,
13519                    selection.goal,
13520                    false,
13521                    text_layout_details,
13522                );
13523                selection.collapse_to(cursor, goal);
13524            });
13525        });
13526    }
13527
13528    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13529        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13530        let text_layout_details = &self.text_layout_details(window);
13531        self.change_selections(Default::default(), window, cx, |s| {
13532            s.move_heads_with(|map, head, goal| {
13533                movement::up(map, head, goal, false, text_layout_details)
13534            })
13535        })
13536    }
13537
13538    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13539        self.take_rename(true, window, cx);
13540
13541        if self.mode.is_single_line() {
13542            cx.propagate();
13543            return;
13544        }
13545
13546        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13547
13548        let text_layout_details = &self.text_layout_details(window);
13549        let selection_count = self.selections.count();
13550        let first_selection = self.selections.first_anchor();
13551
13552        self.change_selections(Default::default(), window, cx, |s| {
13553            s.move_with(|map, selection| {
13554                if !selection.is_empty() {
13555                    selection.goal = SelectionGoal::None;
13556                }
13557                let (cursor, goal) = movement::down(
13558                    map,
13559                    selection.end,
13560                    selection.goal,
13561                    false,
13562                    text_layout_details,
13563                );
13564                selection.collapse_to(cursor, goal);
13565            });
13566        });
13567
13568        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13569        {
13570            cx.propagate();
13571        }
13572    }
13573
13574    pub fn select_page_down(
13575        &mut self,
13576        _: &SelectPageDown,
13577        window: &mut Window,
13578        cx: &mut Context<Self>,
13579    ) {
13580        let Some(row_count) = self.visible_row_count() else {
13581            return;
13582        };
13583
13584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13585
13586        let text_layout_details = &self.text_layout_details(window);
13587
13588        self.change_selections(Default::default(), window, cx, |s| {
13589            s.move_heads_with(|map, head, goal| {
13590                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13591            })
13592        })
13593    }
13594
13595    pub fn move_page_down(
13596        &mut self,
13597        action: &MovePageDown,
13598        window: &mut Window,
13599        cx: &mut Context<Self>,
13600    ) {
13601        if self.take_rename(true, window, cx).is_some() {
13602            return;
13603        }
13604
13605        if self
13606            .context_menu
13607            .borrow_mut()
13608            .as_mut()
13609            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13610            .unwrap_or(false)
13611        {
13612            return;
13613        }
13614
13615        if matches!(self.mode, EditorMode::SingleLine) {
13616            cx.propagate();
13617            return;
13618        }
13619
13620        let Some(row_count) = self.visible_row_count() else {
13621            return;
13622        };
13623
13624        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13625
13626        let effects = if action.center_cursor {
13627            SelectionEffects::scroll(Autoscroll::center())
13628        } else {
13629            SelectionEffects::default()
13630        };
13631
13632        let text_layout_details = &self.text_layout_details(window);
13633        self.change_selections(effects, window, cx, |s| {
13634            s.move_with(|map, selection| {
13635                if !selection.is_empty() {
13636                    selection.goal = SelectionGoal::None;
13637                }
13638                let (cursor, goal) = movement::down_by_rows(
13639                    map,
13640                    selection.end,
13641                    row_count,
13642                    selection.goal,
13643                    false,
13644                    text_layout_details,
13645                );
13646                selection.collapse_to(cursor, goal);
13647            });
13648        });
13649    }
13650
13651    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13652        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13653        let text_layout_details = &self.text_layout_details(window);
13654        self.change_selections(Default::default(), window, cx, |s| {
13655            s.move_heads_with(|map, head, goal| {
13656                movement::down(map, head, goal, false, text_layout_details)
13657            })
13658        });
13659    }
13660
13661    pub fn context_menu_first(
13662        &mut self,
13663        _: &ContextMenuFirst,
13664        window: &mut Window,
13665        cx: &mut Context<Self>,
13666    ) {
13667        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13668            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13669        }
13670    }
13671
13672    pub fn context_menu_prev(
13673        &mut self,
13674        _: &ContextMenuPrevious,
13675        window: &mut Window,
13676        cx: &mut Context<Self>,
13677    ) {
13678        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13679            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13680        }
13681    }
13682
13683    pub fn context_menu_next(
13684        &mut self,
13685        _: &ContextMenuNext,
13686        window: &mut Window,
13687        cx: &mut Context<Self>,
13688    ) {
13689        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13690            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13691        }
13692    }
13693
13694    pub fn context_menu_last(
13695        &mut self,
13696        _: &ContextMenuLast,
13697        window: &mut Window,
13698        cx: &mut Context<Self>,
13699    ) {
13700        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13701            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13702        }
13703    }
13704
13705    pub fn signature_help_prev(
13706        &mut self,
13707        _: &SignatureHelpPrevious,
13708        _: &mut Window,
13709        cx: &mut Context<Self>,
13710    ) {
13711        if let Some(popover) = self.signature_help_state.popover_mut() {
13712            if popover.current_signature == 0 {
13713                popover.current_signature = popover.signatures.len() - 1;
13714            } else {
13715                popover.current_signature -= 1;
13716            }
13717            cx.notify();
13718        }
13719    }
13720
13721    pub fn signature_help_next(
13722        &mut self,
13723        _: &SignatureHelpNext,
13724        _: &mut Window,
13725        cx: &mut Context<Self>,
13726    ) {
13727        if let Some(popover) = self.signature_help_state.popover_mut() {
13728            if popover.current_signature + 1 == popover.signatures.len() {
13729                popover.current_signature = 0;
13730            } else {
13731                popover.current_signature += 1;
13732            }
13733            cx.notify();
13734        }
13735    }
13736
13737    pub fn move_to_previous_word_start(
13738        &mut self,
13739        _: &MoveToPreviousWordStart,
13740        window: &mut Window,
13741        cx: &mut Context<Self>,
13742    ) {
13743        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13744        self.change_selections(Default::default(), window, cx, |s| {
13745            s.move_cursors_with(|map, head, _| {
13746                (
13747                    movement::previous_word_start(map, head),
13748                    SelectionGoal::None,
13749                )
13750            });
13751        })
13752    }
13753
13754    pub fn move_to_previous_subword_start(
13755        &mut self,
13756        _: &MoveToPreviousSubwordStart,
13757        window: &mut Window,
13758        cx: &mut Context<Self>,
13759    ) {
13760        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13761        self.change_selections(Default::default(), window, cx, |s| {
13762            s.move_cursors_with(|map, head, _| {
13763                (
13764                    movement::previous_subword_start(map, head),
13765                    SelectionGoal::None,
13766                )
13767            });
13768        })
13769    }
13770
13771    pub fn select_to_previous_word_start(
13772        &mut self,
13773        _: &SelectToPreviousWordStart,
13774        window: &mut Window,
13775        cx: &mut Context<Self>,
13776    ) {
13777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13778        self.change_selections(Default::default(), window, cx, |s| {
13779            s.move_heads_with(|map, head, _| {
13780                (
13781                    movement::previous_word_start(map, head),
13782                    SelectionGoal::None,
13783                )
13784            });
13785        })
13786    }
13787
13788    pub fn select_to_previous_subword_start(
13789        &mut self,
13790        _: &SelectToPreviousSubwordStart,
13791        window: &mut Window,
13792        cx: &mut Context<Self>,
13793    ) {
13794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13795        self.change_selections(Default::default(), window, cx, |s| {
13796            s.move_heads_with(|map, head, _| {
13797                (
13798                    movement::previous_subword_start(map, head),
13799                    SelectionGoal::None,
13800                )
13801            });
13802        })
13803    }
13804
13805    pub fn delete_to_previous_word_start(
13806        &mut self,
13807        action: &DeleteToPreviousWordStart,
13808        window: &mut Window,
13809        cx: &mut Context<Self>,
13810    ) {
13811        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13812        self.transact(window, cx, |this, window, cx| {
13813            this.select_autoclose_pair(window, cx);
13814            this.change_selections(Default::default(), window, cx, |s| {
13815                s.move_with(|map, selection| {
13816                    if selection.is_empty() {
13817                        let mut cursor = if action.ignore_newlines {
13818                            movement::previous_word_start(map, selection.head())
13819                        } else {
13820                            movement::previous_word_start_or_newline(map, selection.head())
13821                        };
13822                        cursor = movement::adjust_greedy_deletion(
13823                            map,
13824                            selection.head(),
13825                            cursor,
13826                            action.ignore_brackets,
13827                        );
13828                        selection.set_head(cursor, SelectionGoal::None);
13829                    }
13830                });
13831            });
13832            this.insert("", window, cx);
13833        });
13834    }
13835
13836    pub fn delete_to_previous_subword_start(
13837        &mut self,
13838        _: &DeleteToPreviousSubwordStart,
13839        window: &mut Window,
13840        cx: &mut Context<Self>,
13841    ) {
13842        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13843        self.transact(window, cx, |this, window, cx| {
13844            this.select_autoclose_pair(window, cx);
13845            this.change_selections(Default::default(), window, cx, |s| {
13846                s.move_with(|map, selection| {
13847                    if selection.is_empty() {
13848                        let mut cursor = movement::previous_subword_start(map, selection.head());
13849                        cursor =
13850                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13851                        selection.set_head(cursor, SelectionGoal::None);
13852                    }
13853                });
13854            });
13855            this.insert("", window, cx);
13856        });
13857    }
13858
13859    pub fn move_to_next_word_end(
13860        &mut self,
13861        _: &MoveToNextWordEnd,
13862        window: &mut Window,
13863        cx: &mut Context<Self>,
13864    ) {
13865        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13866        self.change_selections(Default::default(), window, cx, |s| {
13867            s.move_cursors_with(|map, head, _| {
13868                (movement::next_word_end(map, head), SelectionGoal::None)
13869            });
13870        })
13871    }
13872
13873    pub fn move_to_next_subword_end(
13874        &mut self,
13875        _: &MoveToNextSubwordEnd,
13876        window: &mut Window,
13877        cx: &mut Context<Self>,
13878    ) {
13879        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13880        self.change_selections(Default::default(), window, cx, |s| {
13881            s.move_cursors_with(|map, head, _| {
13882                (movement::next_subword_end(map, head), SelectionGoal::None)
13883            });
13884        })
13885    }
13886
13887    pub fn select_to_next_word_end(
13888        &mut self,
13889        _: &SelectToNextWordEnd,
13890        window: &mut Window,
13891        cx: &mut Context<Self>,
13892    ) {
13893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13894        self.change_selections(Default::default(), window, cx, |s| {
13895            s.move_heads_with(|map, head, _| {
13896                (movement::next_word_end(map, head), SelectionGoal::None)
13897            });
13898        })
13899    }
13900
13901    pub fn select_to_next_subword_end(
13902        &mut self,
13903        _: &SelectToNextSubwordEnd,
13904        window: &mut Window,
13905        cx: &mut Context<Self>,
13906    ) {
13907        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13908        self.change_selections(Default::default(), window, cx, |s| {
13909            s.move_heads_with(|map, head, _| {
13910                (movement::next_subword_end(map, head), SelectionGoal::None)
13911            });
13912        })
13913    }
13914
13915    pub fn delete_to_next_word_end(
13916        &mut self,
13917        action: &DeleteToNextWordEnd,
13918        window: &mut Window,
13919        cx: &mut Context<Self>,
13920    ) {
13921        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13922        self.transact(window, cx, |this, window, cx| {
13923            this.change_selections(Default::default(), window, cx, |s| {
13924                s.move_with(|map, selection| {
13925                    if selection.is_empty() {
13926                        let mut cursor = if action.ignore_newlines {
13927                            movement::next_word_end(map, selection.head())
13928                        } else {
13929                            movement::next_word_end_or_newline(map, selection.head())
13930                        };
13931                        cursor = movement::adjust_greedy_deletion(
13932                            map,
13933                            selection.head(),
13934                            cursor,
13935                            action.ignore_brackets,
13936                        );
13937                        selection.set_head(cursor, SelectionGoal::None);
13938                    }
13939                });
13940            });
13941            this.insert("", window, cx);
13942        });
13943    }
13944
13945    pub fn delete_to_next_subword_end(
13946        &mut self,
13947        _: &DeleteToNextSubwordEnd,
13948        window: &mut Window,
13949        cx: &mut Context<Self>,
13950    ) {
13951        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13952        self.transact(window, cx, |this, window, cx| {
13953            this.change_selections(Default::default(), window, cx, |s| {
13954                s.move_with(|map, selection| {
13955                    if selection.is_empty() {
13956                        let mut cursor = movement::next_subword_end(map, selection.head());
13957                        cursor =
13958                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13959                        selection.set_head(cursor, SelectionGoal::None);
13960                    }
13961                });
13962            });
13963            this.insert("", window, cx);
13964        });
13965    }
13966
13967    pub fn move_to_beginning_of_line(
13968        &mut self,
13969        action: &MoveToBeginningOfLine,
13970        window: &mut Window,
13971        cx: &mut Context<Self>,
13972    ) {
13973        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13974        self.change_selections(Default::default(), window, cx, |s| {
13975            s.move_cursors_with(|map, head, _| {
13976                (
13977                    movement::indented_line_beginning(
13978                        map,
13979                        head,
13980                        action.stop_at_soft_wraps,
13981                        action.stop_at_indent,
13982                    ),
13983                    SelectionGoal::None,
13984                )
13985            });
13986        })
13987    }
13988
13989    pub fn select_to_beginning_of_line(
13990        &mut self,
13991        action: &SelectToBeginningOfLine,
13992        window: &mut Window,
13993        cx: &mut Context<Self>,
13994    ) {
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13996        self.change_selections(Default::default(), window, cx, |s| {
13997            s.move_heads_with(|map, head, _| {
13998                (
13999                    movement::indented_line_beginning(
14000                        map,
14001                        head,
14002                        action.stop_at_soft_wraps,
14003                        action.stop_at_indent,
14004                    ),
14005                    SelectionGoal::None,
14006                )
14007            });
14008        });
14009    }
14010
14011    pub fn delete_to_beginning_of_line(
14012        &mut self,
14013        action: &DeleteToBeginningOfLine,
14014        window: &mut Window,
14015        cx: &mut Context<Self>,
14016    ) {
14017        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14018        self.transact(window, cx, |this, window, cx| {
14019            this.change_selections(Default::default(), window, cx, |s| {
14020                s.move_with(|_, selection| {
14021                    selection.reversed = true;
14022                });
14023            });
14024
14025            this.select_to_beginning_of_line(
14026                &SelectToBeginningOfLine {
14027                    stop_at_soft_wraps: false,
14028                    stop_at_indent: action.stop_at_indent,
14029                },
14030                window,
14031                cx,
14032            );
14033            this.backspace(&Backspace, window, cx);
14034        });
14035    }
14036
14037    pub fn move_to_end_of_line(
14038        &mut self,
14039        action: &MoveToEndOfLine,
14040        window: &mut Window,
14041        cx: &mut Context<Self>,
14042    ) {
14043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14044        self.change_selections(Default::default(), window, cx, |s| {
14045            s.move_cursors_with(|map, head, _| {
14046                (
14047                    movement::line_end(map, head, action.stop_at_soft_wraps),
14048                    SelectionGoal::None,
14049                )
14050            });
14051        })
14052    }
14053
14054    pub fn select_to_end_of_line(
14055        &mut self,
14056        action: &SelectToEndOfLine,
14057        window: &mut Window,
14058        cx: &mut Context<Self>,
14059    ) {
14060        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14061        self.change_selections(Default::default(), window, cx, |s| {
14062            s.move_heads_with(|map, head, _| {
14063                (
14064                    movement::line_end(map, head, action.stop_at_soft_wraps),
14065                    SelectionGoal::None,
14066                )
14067            });
14068        })
14069    }
14070
14071    pub fn delete_to_end_of_line(
14072        &mut self,
14073        _: &DeleteToEndOfLine,
14074        window: &mut Window,
14075        cx: &mut Context<Self>,
14076    ) {
14077        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14078        self.transact(window, cx, |this, window, cx| {
14079            this.select_to_end_of_line(
14080                &SelectToEndOfLine {
14081                    stop_at_soft_wraps: false,
14082                },
14083                window,
14084                cx,
14085            );
14086            this.delete(&Delete, window, cx);
14087        });
14088    }
14089
14090    pub fn cut_to_end_of_line(
14091        &mut self,
14092        action: &CutToEndOfLine,
14093        window: &mut Window,
14094        cx: &mut Context<Self>,
14095    ) {
14096        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14097        self.transact(window, cx, |this, window, cx| {
14098            this.select_to_end_of_line(
14099                &SelectToEndOfLine {
14100                    stop_at_soft_wraps: false,
14101                },
14102                window,
14103                cx,
14104            );
14105            if !action.stop_at_newlines {
14106                this.change_selections(Default::default(), window, cx, |s| {
14107                    s.move_with(|_, sel| {
14108                        if sel.is_empty() {
14109                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14110                        }
14111                    });
14112                });
14113            }
14114            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14115            let item = this.cut_common(false, window, cx);
14116            cx.write_to_clipboard(item);
14117        });
14118    }
14119
14120    pub fn move_to_start_of_paragraph(
14121        &mut self,
14122        _: &MoveToStartOfParagraph,
14123        window: &mut Window,
14124        cx: &mut Context<Self>,
14125    ) {
14126        if matches!(self.mode, EditorMode::SingleLine) {
14127            cx.propagate();
14128            return;
14129        }
14130        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14131        self.change_selections(Default::default(), window, cx, |s| {
14132            s.move_with(|map, selection| {
14133                selection.collapse_to(
14134                    movement::start_of_paragraph(map, selection.head(), 1),
14135                    SelectionGoal::None,
14136                )
14137            });
14138        })
14139    }
14140
14141    pub fn move_to_end_of_paragraph(
14142        &mut self,
14143        _: &MoveToEndOfParagraph,
14144        window: &mut Window,
14145        cx: &mut Context<Self>,
14146    ) {
14147        if matches!(self.mode, EditorMode::SingleLine) {
14148            cx.propagate();
14149            return;
14150        }
14151        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14152        self.change_selections(Default::default(), window, cx, |s| {
14153            s.move_with(|map, selection| {
14154                selection.collapse_to(
14155                    movement::end_of_paragraph(map, selection.head(), 1),
14156                    SelectionGoal::None,
14157                )
14158            });
14159        })
14160    }
14161
14162    pub fn select_to_start_of_paragraph(
14163        &mut self,
14164        _: &SelectToStartOfParagraph,
14165        window: &mut Window,
14166        cx: &mut Context<Self>,
14167    ) {
14168        if matches!(self.mode, EditorMode::SingleLine) {
14169            cx.propagate();
14170            return;
14171        }
14172        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14173        self.change_selections(Default::default(), window, cx, |s| {
14174            s.move_heads_with(|map, head, _| {
14175                (
14176                    movement::start_of_paragraph(map, head, 1),
14177                    SelectionGoal::None,
14178                )
14179            });
14180        })
14181    }
14182
14183    pub fn select_to_end_of_paragraph(
14184        &mut self,
14185        _: &SelectToEndOfParagraph,
14186        window: &mut Window,
14187        cx: &mut Context<Self>,
14188    ) {
14189        if matches!(self.mode, EditorMode::SingleLine) {
14190            cx.propagate();
14191            return;
14192        }
14193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14194        self.change_selections(Default::default(), window, cx, |s| {
14195            s.move_heads_with(|map, head, _| {
14196                (
14197                    movement::end_of_paragraph(map, head, 1),
14198                    SelectionGoal::None,
14199                )
14200            });
14201        })
14202    }
14203
14204    pub fn move_to_start_of_excerpt(
14205        &mut self,
14206        _: &MoveToStartOfExcerpt,
14207        window: &mut Window,
14208        cx: &mut Context<Self>,
14209    ) {
14210        if matches!(self.mode, EditorMode::SingleLine) {
14211            cx.propagate();
14212            return;
14213        }
14214        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14215        self.change_selections(Default::default(), window, cx, |s| {
14216            s.move_with(|map, selection| {
14217                selection.collapse_to(
14218                    movement::start_of_excerpt(
14219                        map,
14220                        selection.head(),
14221                        workspace::searchable::Direction::Prev,
14222                    ),
14223                    SelectionGoal::None,
14224                )
14225            });
14226        })
14227    }
14228
14229    pub fn move_to_start_of_next_excerpt(
14230        &mut self,
14231        _: &MoveToStartOfNextExcerpt,
14232        window: &mut Window,
14233        cx: &mut Context<Self>,
14234    ) {
14235        if matches!(self.mode, EditorMode::SingleLine) {
14236            cx.propagate();
14237            return;
14238        }
14239
14240        self.change_selections(Default::default(), window, cx, |s| {
14241            s.move_with(|map, selection| {
14242                selection.collapse_to(
14243                    movement::start_of_excerpt(
14244                        map,
14245                        selection.head(),
14246                        workspace::searchable::Direction::Next,
14247                    ),
14248                    SelectionGoal::None,
14249                )
14250            });
14251        })
14252    }
14253
14254    pub fn move_to_end_of_excerpt(
14255        &mut self,
14256        _: &MoveToEndOfExcerpt,
14257        window: &mut Window,
14258        cx: &mut Context<Self>,
14259    ) {
14260        if matches!(self.mode, EditorMode::SingleLine) {
14261            cx.propagate();
14262            return;
14263        }
14264        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14265        self.change_selections(Default::default(), window, cx, |s| {
14266            s.move_with(|map, selection| {
14267                selection.collapse_to(
14268                    movement::end_of_excerpt(
14269                        map,
14270                        selection.head(),
14271                        workspace::searchable::Direction::Next,
14272                    ),
14273                    SelectionGoal::None,
14274                )
14275            });
14276        })
14277    }
14278
14279    pub fn move_to_end_of_previous_excerpt(
14280        &mut self,
14281        _: &MoveToEndOfPreviousExcerpt,
14282        window: &mut Window,
14283        cx: &mut Context<Self>,
14284    ) {
14285        if matches!(self.mode, EditorMode::SingleLine) {
14286            cx.propagate();
14287            return;
14288        }
14289        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14290        self.change_selections(Default::default(), window, cx, |s| {
14291            s.move_with(|map, selection| {
14292                selection.collapse_to(
14293                    movement::end_of_excerpt(
14294                        map,
14295                        selection.head(),
14296                        workspace::searchable::Direction::Prev,
14297                    ),
14298                    SelectionGoal::None,
14299                )
14300            });
14301        })
14302    }
14303
14304    pub fn select_to_start_of_excerpt(
14305        &mut self,
14306        _: &SelectToStartOfExcerpt,
14307        window: &mut Window,
14308        cx: &mut Context<Self>,
14309    ) {
14310        if matches!(self.mode, EditorMode::SingleLine) {
14311            cx.propagate();
14312            return;
14313        }
14314        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14315        self.change_selections(Default::default(), window, cx, |s| {
14316            s.move_heads_with(|map, head, _| {
14317                (
14318                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14319                    SelectionGoal::None,
14320                )
14321            });
14322        })
14323    }
14324
14325    pub fn select_to_start_of_next_excerpt(
14326        &mut self,
14327        _: &SelectToStartOfNextExcerpt,
14328        window: &mut Window,
14329        cx: &mut Context<Self>,
14330    ) {
14331        if matches!(self.mode, EditorMode::SingleLine) {
14332            cx.propagate();
14333            return;
14334        }
14335        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14336        self.change_selections(Default::default(), window, cx, |s| {
14337            s.move_heads_with(|map, head, _| {
14338                (
14339                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14340                    SelectionGoal::None,
14341                )
14342            });
14343        })
14344    }
14345
14346    pub fn select_to_end_of_excerpt(
14347        &mut self,
14348        _: &SelectToEndOfExcerpt,
14349        window: &mut Window,
14350        cx: &mut Context<Self>,
14351    ) {
14352        if matches!(self.mode, EditorMode::SingleLine) {
14353            cx.propagate();
14354            return;
14355        }
14356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14357        self.change_selections(Default::default(), window, cx, |s| {
14358            s.move_heads_with(|map, head, _| {
14359                (
14360                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14361                    SelectionGoal::None,
14362                )
14363            });
14364        })
14365    }
14366
14367    pub fn select_to_end_of_previous_excerpt(
14368        &mut self,
14369        _: &SelectToEndOfPreviousExcerpt,
14370        window: &mut Window,
14371        cx: &mut Context<Self>,
14372    ) {
14373        if matches!(self.mode, EditorMode::SingleLine) {
14374            cx.propagate();
14375            return;
14376        }
14377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14378        self.change_selections(Default::default(), window, cx, |s| {
14379            s.move_heads_with(|map, head, _| {
14380                (
14381                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14382                    SelectionGoal::None,
14383                )
14384            });
14385        })
14386    }
14387
14388    pub fn move_to_beginning(
14389        &mut self,
14390        _: &MoveToBeginning,
14391        window: &mut Window,
14392        cx: &mut Context<Self>,
14393    ) {
14394        if matches!(self.mode, EditorMode::SingleLine) {
14395            cx.propagate();
14396            return;
14397        }
14398        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14399        self.change_selections(Default::default(), window, cx, |s| {
14400            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14401        });
14402    }
14403
14404    pub fn select_to_beginning(
14405        &mut self,
14406        _: &SelectToBeginning,
14407        window: &mut Window,
14408        cx: &mut Context<Self>,
14409    ) {
14410        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14411        selection.set_head(Point::zero(), SelectionGoal::None);
14412        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14413        self.change_selections(Default::default(), window, cx, |s| {
14414            s.select(vec![selection]);
14415        });
14416    }
14417
14418    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14419        if matches!(self.mode, EditorMode::SingleLine) {
14420            cx.propagate();
14421            return;
14422        }
14423        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14424        let cursor = self.buffer.read(cx).read(cx).len();
14425        self.change_selections(Default::default(), window, cx, |s| {
14426            s.select_ranges(vec![cursor..cursor])
14427        });
14428    }
14429
14430    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14431        self.nav_history = nav_history;
14432    }
14433
14434    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14435        self.nav_history.as_ref()
14436    }
14437
14438    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14439        self.push_to_nav_history(
14440            self.selections.newest_anchor().head(),
14441            None,
14442            false,
14443            true,
14444            cx,
14445        );
14446    }
14447
14448    fn push_to_nav_history(
14449        &mut self,
14450        cursor_anchor: Anchor,
14451        new_position: Option<Point>,
14452        is_deactivate: bool,
14453        always: bool,
14454        cx: &mut Context<Self>,
14455    ) {
14456        if let Some(nav_history) = self.nav_history.as_mut() {
14457            let buffer = self.buffer.read(cx).read(cx);
14458            let cursor_position = cursor_anchor.to_point(&buffer);
14459            let scroll_state = self.scroll_manager.anchor();
14460            let scroll_top_row = scroll_state.top_row(&buffer);
14461            drop(buffer);
14462
14463            if let Some(new_position) = new_position {
14464                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14465                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14466                    return;
14467                }
14468            }
14469
14470            nav_history.push(
14471                Some(NavigationData {
14472                    cursor_anchor,
14473                    cursor_position,
14474                    scroll_anchor: scroll_state,
14475                    scroll_top_row,
14476                }),
14477                cx,
14478            );
14479            cx.emit(EditorEvent::PushedToNavHistory {
14480                anchor: cursor_anchor,
14481                is_deactivate,
14482            })
14483        }
14484    }
14485
14486    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14487        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14488        let buffer = self.buffer.read(cx).snapshot(cx);
14489        let mut selection = self
14490            .selections
14491            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14492        selection.set_head(buffer.len(), SelectionGoal::None);
14493        self.change_selections(Default::default(), window, cx, |s| {
14494            s.select(vec![selection]);
14495        });
14496    }
14497
14498    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14499        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14500        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14501            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14502        });
14503    }
14504
14505    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14507        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14508        let mut selections = self.selections.all::<Point>(&display_map);
14509        let max_point = display_map.buffer_snapshot().max_point();
14510        for selection in &mut selections {
14511            let rows = selection.spanned_rows(true, &display_map);
14512            selection.start = Point::new(rows.start.0, 0);
14513            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14514            selection.reversed = false;
14515        }
14516        self.change_selections(Default::default(), window, cx, |s| {
14517            s.select(selections);
14518        });
14519    }
14520
14521    pub fn split_selection_into_lines(
14522        &mut self,
14523        action: &SplitSelectionIntoLines,
14524        window: &mut Window,
14525        cx: &mut Context<Self>,
14526    ) {
14527        let selections = self
14528            .selections
14529            .all::<Point>(&self.display_snapshot(cx))
14530            .into_iter()
14531            .map(|selection| selection.start..selection.end)
14532            .collect::<Vec<_>>();
14533        self.unfold_ranges(&selections, true, true, cx);
14534
14535        let mut new_selection_ranges = Vec::new();
14536        {
14537            let buffer = self.buffer.read(cx).read(cx);
14538            for selection in selections {
14539                for row in selection.start.row..selection.end.row {
14540                    let line_start = Point::new(row, 0);
14541                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14542
14543                    if action.keep_selections {
14544                        // Keep the selection range for each line
14545                        let selection_start = if row == selection.start.row {
14546                            selection.start
14547                        } else {
14548                            line_start
14549                        };
14550                        new_selection_ranges.push(selection_start..line_end);
14551                    } else {
14552                        // Collapse to cursor at end of line
14553                        new_selection_ranges.push(line_end..line_end);
14554                    }
14555                }
14556
14557                let is_multiline_selection = selection.start.row != selection.end.row;
14558                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14559                // so this action feels more ergonomic when paired with other selection operations
14560                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14561                if !should_skip_last {
14562                    if action.keep_selections {
14563                        if is_multiline_selection {
14564                            let line_start = Point::new(selection.end.row, 0);
14565                            new_selection_ranges.push(line_start..selection.end);
14566                        } else {
14567                            new_selection_ranges.push(selection.start..selection.end);
14568                        }
14569                    } else {
14570                        new_selection_ranges.push(selection.end..selection.end);
14571                    }
14572                }
14573            }
14574        }
14575        self.change_selections(Default::default(), window, cx, |s| {
14576            s.select_ranges(new_selection_ranges);
14577        });
14578    }
14579
14580    pub fn add_selection_above(
14581        &mut self,
14582        action: &AddSelectionAbove,
14583        window: &mut Window,
14584        cx: &mut Context<Self>,
14585    ) {
14586        self.add_selection(true, action.skip_soft_wrap, window, cx);
14587    }
14588
14589    pub fn add_selection_below(
14590        &mut self,
14591        action: &AddSelectionBelow,
14592        window: &mut Window,
14593        cx: &mut Context<Self>,
14594    ) {
14595        self.add_selection(false, action.skip_soft_wrap, window, cx);
14596    }
14597
14598    fn add_selection(
14599        &mut self,
14600        above: bool,
14601        skip_soft_wrap: bool,
14602        window: &mut Window,
14603        cx: &mut Context<Self>,
14604    ) {
14605        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14606
14607        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14608        let all_selections = self.selections.all::<Point>(&display_map);
14609        let text_layout_details = self.text_layout_details(window);
14610
14611        let (mut columnar_selections, new_selections_to_columnarize) = {
14612            if let Some(state) = self.add_selections_state.as_ref() {
14613                let columnar_selection_ids: HashSet<_> = state
14614                    .groups
14615                    .iter()
14616                    .flat_map(|group| group.stack.iter())
14617                    .copied()
14618                    .collect();
14619
14620                all_selections
14621                    .into_iter()
14622                    .partition(|s| columnar_selection_ids.contains(&s.id))
14623            } else {
14624                (Vec::new(), all_selections)
14625            }
14626        };
14627
14628        let mut state = self
14629            .add_selections_state
14630            .take()
14631            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14632
14633        for selection in new_selections_to_columnarize {
14634            let range = selection.display_range(&display_map).sorted();
14635            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14636            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14637            let positions = start_x.min(end_x)..start_x.max(end_x);
14638            let mut stack = Vec::new();
14639            for row in range.start.row().0..=range.end.row().0 {
14640                if let Some(selection) = self.selections.build_columnar_selection(
14641                    &display_map,
14642                    DisplayRow(row),
14643                    &positions,
14644                    selection.reversed,
14645                    &text_layout_details,
14646                ) {
14647                    stack.push(selection.id);
14648                    columnar_selections.push(selection);
14649                }
14650            }
14651            if !stack.is_empty() {
14652                if above {
14653                    stack.reverse();
14654                }
14655                state.groups.push(AddSelectionsGroup { above, stack });
14656            }
14657        }
14658
14659        let mut final_selections = Vec::new();
14660        let end_row = if above {
14661            DisplayRow(0)
14662        } else {
14663            display_map.max_point().row()
14664        };
14665
14666        let mut last_added_item_per_group = HashMap::default();
14667        for group in state.groups.iter_mut() {
14668            if let Some(last_id) = group.stack.last() {
14669                last_added_item_per_group.insert(*last_id, group);
14670            }
14671        }
14672
14673        for selection in columnar_selections {
14674            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14675                if above == group.above {
14676                    let range = selection.display_range(&display_map).sorted();
14677                    debug_assert_eq!(range.start.row(), range.end.row());
14678                    let mut row = range.start.row();
14679                    let positions =
14680                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14681                            Pixels::from(start)..Pixels::from(end)
14682                        } else {
14683                            let start_x =
14684                                display_map.x_for_display_point(range.start, &text_layout_details);
14685                            let end_x =
14686                                display_map.x_for_display_point(range.end, &text_layout_details);
14687                            start_x.min(end_x)..start_x.max(end_x)
14688                        };
14689
14690                    let mut maybe_new_selection = None;
14691                    let direction = if above { -1 } else { 1 };
14692
14693                    while row != end_row {
14694                        if skip_soft_wrap {
14695                            row = display_map
14696                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14697                                .row();
14698                        } else if above {
14699                            row.0 -= 1;
14700                        } else {
14701                            row.0 += 1;
14702                        }
14703
14704                        if let Some(new_selection) = self.selections.build_columnar_selection(
14705                            &display_map,
14706                            row,
14707                            &positions,
14708                            selection.reversed,
14709                            &text_layout_details,
14710                        ) {
14711                            maybe_new_selection = Some(new_selection);
14712                            break;
14713                        }
14714                    }
14715
14716                    if let Some(new_selection) = maybe_new_selection {
14717                        group.stack.push(new_selection.id);
14718                        if above {
14719                            final_selections.push(new_selection);
14720                            final_selections.push(selection);
14721                        } else {
14722                            final_selections.push(selection);
14723                            final_selections.push(new_selection);
14724                        }
14725                    } else {
14726                        final_selections.push(selection);
14727                    }
14728                } else {
14729                    group.stack.pop();
14730                }
14731            } else {
14732                final_selections.push(selection);
14733            }
14734        }
14735
14736        self.change_selections(Default::default(), window, cx, |s| {
14737            s.select(final_selections);
14738        });
14739
14740        let final_selection_ids: HashSet<_> = self
14741            .selections
14742            .all::<Point>(&display_map)
14743            .iter()
14744            .map(|s| s.id)
14745            .collect();
14746        state.groups.retain_mut(|group| {
14747            // selections might get merged above so we remove invalid items from stacks
14748            group.stack.retain(|id| final_selection_ids.contains(id));
14749
14750            // single selection in stack can be treated as initial state
14751            group.stack.len() > 1
14752        });
14753
14754        if !state.groups.is_empty() {
14755            self.add_selections_state = Some(state);
14756        }
14757    }
14758
14759    fn select_match_ranges(
14760        &mut self,
14761        range: Range<MultiBufferOffset>,
14762        reversed: bool,
14763        replace_newest: bool,
14764        auto_scroll: Option<Autoscroll>,
14765        window: &mut Window,
14766        cx: &mut Context<Editor>,
14767    ) {
14768        self.unfold_ranges(
14769            std::slice::from_ref(&range),
14770            false,
14771            auto_scroll.is_some(),
14772            cx,
14773        );
14774        let effects = if let Some(scroll) = auto_scroll {
14775            SelectionEffects::scroll(scroll)
14776        } else {
14777            SelectionEffects::no_scroll()
14778        };
14779        self.change_selections(effects, window, cx, |s| {
14780            if replace_newest {
14781                s.delete(s.newest_anchor().id);
14782            }
14783            if reversed {
14784                s.insert_range(range.end..range.start);
14785            } else {
14786                s.insert_range(range);
14787            }
14788        });
14789    }
14790
14791    pub fn select_next_match_internal(
14792        &mut self,
14793        display_map: &DisplaySnapshot,
14794        replace_newest: bool,
14795        autoscroll: Option<Autoscroll>,
14796        window: &mut Window,
14797        cx: &mut Context<Self>,
14798    ) -> Result<()> {
14799        let buffer = display_map.buffer_snapshot();
14800        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14801        if let Some(mut select_next_state) = self.select_next_state.take() {
14802            let query = &select_next_state.query;
14803            if !select_next_state.done {
14804                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14805                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14806                let mut next_selected_range = None;
14807
14808                let bytes_after_last_selection =
14809                    buffer.bytes_in_range(last_selection.end..buffer.len());
14810                let bytes_before_first_selection =
14811                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
14812                let query_matches = query
14813                    .stream_find_iter(bytes_after_last_selection)
14814                    .map(|result| (last_selection.end, result))
14815                    .chain(
14816                        query
14817                            .stream_find_iter(bytes_before_first_selection)
14818                            .map(|result| (MultiBufferOffset(0), result)),
14819                    );
14820
14821                for (start_offset, query_match) in query_matches {
14822                    let query_match = query_match.unwrap(); // can only fail due to I/O
14823                    let offset_range =
14824                        start_offset + query_match.start()..start_offset + query_match.end();
14825
14826                    if !select_next_state.wordwise
14827                        || (!buffer.is_inside_word(offset_range.start, None)
14828                            && !buffer.is_inside_word(offset_range.end, None))
14829                    {
14830                        let idx = selections
14831                            .partition_point(|selection| selection.end <= offset_range.start);
14832                        let overlaps = selections
14833                            .get(idx)
14834                            .map_or(false, |selection| selection.start < offset_range.end);
14835
14836                        if !overlaps {
14837                            next_selected_range = Some(offset_range);
14838                            break;
14839                        }
14840                    }
14841                }
14842
14843                if let Some(next_selected_range) = next_selected_range {
14844                    self.select_match_ranges(
14845                        next_selected_range,
14846                        last_selection.reversed,
14847                        replace_newest,
14848                        autoscroll,
14849                        window,
14850                        cx,
14851                    );
14852                } else {
14853                    select_next_state.done = true;
14854                }
14855            }
14856
14857            self.select_next_state = Some(select_next_state);
14858        } else {
14859            let mut only_carets = true;
14860            let mut same_text_selected = true;
14861            let mut selected_text = None;
14862
14863            let mut selections_iter = selections.iter().peekable();
14864            while let Some(selection) = selections_iter.next() {
14865                if selection.start != selection.end {
14866                    only_carets = false;
14867                }
14868
14869                if same_text_selected {
14870                    if selected_text.is_none() {
14871                        selected_text =
14872                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14873                    }
14874
14875                    if let Some(next_selection) = selections_iter.peek() {
14876                        if next_selection.len() == selection.len() {
14877                            let next_selected_text = buffer
14878                                .text_for_range(next_selection.range())
14879                                .collect::<String>();
14880                            if Some(next_selected_text) != selected_text {
14881                                same_text_selected = false;
14882                                selected_text = None;
14883                            }
14884                        } else {
14885                            same_text_selected = false;
14886                            selected_text = None;
14887                        }
14888                    }
14889                }
14890            }
14891
14892            if only_carets {
14893                for selection in &mut selections {
14894                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14895                    selection.start = word_range.start;
14896                    selection.end = word_range.end;
14897                    selection.goal = SelectionGoal::None;
14898                    selection.reversed = false;
14899                    self.select_match_ranges(
14900                        selection.start..selection.end,
14901                        selection.reversed,
14902                        replace_newest,
14903                        autoscroll,
14904                        window,
14905                        cx,
14906                    );
14907                }
14908
14909                if selections.len() == 1 {
14910                    let selection = selections
14911                        .last()
14912                        .expect("ensured that there's only one selection");
14913                    let query = buffer
14914                        .text_for_range(selection.start..selection.end)
14915                        .collect::<String>();
14916                    let is_empty = query.is_empty();
14917                    let select_state = SelectNextState {
14918                        query: self.build_query(&[query], cx)?,
14919                        wordwise: true,
14920                        done: is_empty,
14921                    };
14922                    self.select_next_state = Some(select_state);
14923                } else {
14924                    self.select_next_state = None;
14925                }
14926            } else if let Some(selected_text) = selected_text {
14927                self.select_next_state = Some(SelectNextState {
14928                    query: self.build_query(&[selected_text], cx)?,
14929                    wordwise: false,
14930                    done: false,
14931                });
14932                self.select_next_match_internal(
14933                    display_map,
14934                    replace_newest,
14935                    autoscroll,
14936                    window,
14937                    cx,
14938                )?;
14939            }
14940        }
14941        Ok(())
14942    }
14943
14944    pub fn select_all_matches(
14945        &mut self,
14946        _action: &SelectAllMatches,
14947        window: &mut Window,
14948        cx: &mut Context<Self>,
14949    ) -> Result<()> {
14950        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14951
14952        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14953
14954        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14955        let Some(select_next_state) = self.select_next_state.as_mut() else {
14956            return Ok(());
14957        };
14958        if select_next_state.done {
14959            return Ok(());
14960        }
14961
14962        let mut new_selections = Vec::new();
14963
14964        let reversed = self
14965            .selections
14966            .oldest::<MultiBufferOffset>(&display_map)
14967            .reversed;
14968        let buffer = display_map.buffer_snapshot();
14969        let query_matches = select_next_state
14970            .query
14971            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
14972
14973        for query_match in query_matches.into_iter() {
14974            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14975            let offset_range = if reversed {
14976                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
14977            } else {
14978                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
14979            };
14980
14981            if !select_next_state.wordwise
14982                || (!buffer.is_inside_word(offset_range.start, None)
14983                    && !buffer.is_inside_word(offset_range.end, None))
14984            {
14985                new_selections.push(offset_range.start..offset_range.end);
14986            }
14987        }
14988
14989        select_next_state.done = true;
14990
14991        if new_selections.is_empty() {
14992            log::error!("bug: new_selections is empty in select_all_matches");
14993            return Ok(());
14994        }
14995
14996        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14997        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14998            selections.select_ranges(new_selections)
14999        });
15000
15001        Ok(())
15002    }
15003
15004    pub fn select_next(
15005        &mut self,
15006        action: &SelectNext,
15007        window: &mut Window,
15008        cx: &mut Context<Self>,
15009    ) -> Result<()> {
15010        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15011        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15012        self.select_next_match_internal(
15013            &display_map,
15014            action.replace_newest,
15015            Some(Autoscroll::newest()),
15016            window,
15017            cx,
15018        )?;
15019        Ok(())
15020    }
15021
15022    pub fn select_previous(
15023        &mut self,
15024        action: &SelectPrevious,
15025        window: &mut Window,
15026        cx: &mut Context<Self>,
15027    ) -> Result<()> {
15028        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15029        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15030        let buffer = display_map.buffer_snapshot();
15031        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15032        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15033            let query = &select_prev_state.query;
15034            if !select_prev_state.done {
15035                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15036                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15037                let mut next_selected_range = None;
15038                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15039                let bytes_before_last_selection =
15040                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15041                let bytes_after_first_selection =
15042                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15043                let query_matches = query
15044                    .stream_find_iter(bytes_before_last_selection)
15045                    .map(|result| (last_selection.start, result))
15046                    .chain(
15047                        query
15048                            .stream_find_iter(bytes_after_first_selection)
15049                            .map(|result| (buffer.len(), result)),
15050                    );
15051                for (end_offset, query_match) in query_matches {
15052                    let query_match = query_match.unwrap(); // can only fail due to I/O
15053                    let offset_range =
15054                        end_offset - query_match.end()..end_offset - query_match.start();
15055
15056                    if !select_prev_state.wordwise
15057                        || (!buffer.is_inside_word(offset_range.start, None)
15058                            && !buffer.is_inside_word(offset_range.end, None))
15059                    {
15060                        next_selected_range = Some(offset_range);
15061                        break;
15062                    }
15063                }
15064
15065                if let Some(next_selected_range) = next_selected_range {
15066                    self.select_match_ranges(
15067                        next_selected_range,
15068                        last_selection.reversed,
15069                        action.replace_newest,
15070                        Some(Autoscroll::newest()),
15071                        window,
15072                        cx,
15073                    );
15074                } else {
15075                    select_prev_state.done = true;
15076                }
15077            }
15078
15079            self.select_prev_state = Some(select_prev_state);
15080        } else {
15081            let mut only_carets = true;
15082            let mut same_text_selected = true;
15083            let mut selected_text = None;
15084
15085            let mut selections_iter = selections.iter().peekable();
15086            while let Some(selection) = selections_iter.next() {
15087                if selection.start != selection.end {
15088                    only_carets = false;
15089                }
15090
15091                if same_text_selected {
15092                    if selected_text.is_none() {
15093                        selected_text =
15094                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15095                    }
15096
15097                    if let Some(next_selection) = selections_iter.peek() {
15098                        if next_selection.len() == selection.len() {
15099                            let next_selected_text = buffer
15100                                .text_for_range(next_selection.range())
15101                                .collect::<String>();
15102                            if Some(next_selected_text) != selected_text {
15103                                same_text_selected = false;
15104                                selected_text = None;
15105                            }
15106                        } else {
15107                            same_text_selected = false;
15108                            selected_text = None;
15109                        }
15110                    }
15111                }
15112            }
15113
15114            if only_carets {
15115                for selection in &mut selections {
15116                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15117                    selection.start = word_range.start;
15118                    selection.end = word_range.end;
15119                    selection.goal = SelectionGoal::None;
15120                    selection.reversed = false;
15121                    self.select_match_ranges(
15122                        selection.start..selection.end,
15123                        selection.reversed,
15124                        action.replace_newest,
15125                        Some(Autoscroll::newest()),
15126                        window,
15127                        cx,
15128                    );
15129                }
15130                if selections.len() == 1 {
15131                    let selection = selections
15132                        .last()
15133                        .expect("ensured that there's only one selection");
15134                    let query = buffer
15135                        .text_for_range(selection.start..selection.end)
15136                        .collect::<String>();
15137                    let is_empty = query.is_empty();
15138                    let select_state = SelectNextState {
15139                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15140                        wordwise: true,
15141                        done: is_empty,
15142                    };
15143                    self.select_prev_state = Some(select_state);
15144                } else {
15145                    self.select_prev_state = None;
15146                }
15147            } else if let Some(selected_text) = selected_text {
15148                self.select_prev_state = Some(SelectNextState {
15149                    query: self
15150                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15151                    wordwise: false,
15152                    done: false,
15153                });
15154                self.select_previous(action, window, cx)?;
15155            }
15156        }
15157        Ok(())
15158    }
15159
15160    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15161    /// setting the case sensitivity based on the global
15162    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15163    /// editor's settings.
15164    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15165    where
15166        I: IntoIterator<Item = P>,
15167        P: AsRef<[u8]>,
15168    {
15169        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15170            || EditorSettings::get_global(cx).search.case_sensitive,
15171            |value| value,
15172        );
15173
15174        let mut builder = AhoCorasickBuilder::new();
15175        builder.ascii_case_insensitive(!case_sensitive);
15176        builder.build(patterns)
15177    }
15178
15179    pub fn find_next_match(
15180        &mut self,
15181        _: &FindNextMatch,
15182        window: &mut Window,
15183        cx: &mut Context<Self>,
15184    ) -> Result<()> {
15185        let selections = self.selections.disjoint_anchors_arc();
15186        match selections.first() {
15187            Some(first) if selections.len() >= 2 => {
15188                self.change_selections(Default::default(), window, cx, |s| {
15189                    s.select_ranges([first.range()]);
15190                });
15191            }
15192            _ => self.select_next(
15193                &SelectNext {
15194                    replace_newest: true,
15195                },
15196                window,
15197                cx,
15198            )?,
15199        }
15200        Ok(())
15201    }
15202
15203    pub fn find_previous_match(
15204        &mut self,
15205        _: &FindPreviousMatch,
15206        window: &mut Window,
15207        cx: &mut Context<Self>,
15208    ) -> Result<()> {
15209        let selections = self.selections.disjoint_anchors_arc();
15210        match selections.last() {
15211            Some(last) if selections.len() >= 2 => {
15212                self.change_selections(Default::default(), window, cx, |s| {
15213                    s.select_ranges([last.range()]);
15214                });
15215            }
15216            _ => self.select_previous(
15217                &SelectPrevious {
15218                    replace_newest: true,
15219                },
15220                window,
15221                cx,
15222            )?,
15223        }
15224        Ok(())
15225    }
15226
15227    pub fn toggle_comments(
15228        &mut self,
15229        action: &ToggleComments,
15230        window: &mut Window,
15231        cx: &mut Context<Self>,
15232    ) {
15233        if self.read_only(cx) {
15234            return;
15235        }
15236        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15237        let text_layout_details = &self.text_layout_details(window);
15238        self.transact(window, cx, |this, window, cx| {
15239            let mut selections = this
15240                .selections
15241                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15242            let mut edits = Vec::new();
15243            let mut selection_edit_ranges = Vec::new();
15244            let mut last_toggled_row = None;
15245            let snapshot = this.buffer.read(cx).read(cx);
15246            let empty_str: Arc<str> = Arc::default();
15247            let mut suffixes_inserted = Vec::new();
15248            let ignore_indent = action.ignore_indent;
15249
15250            fn comment_prefix_range(
15251                snapshot: &MultiBufferSnapshot,
15252                row: MultiBufferRow,
15253                comment_prefix: &str,
15254                comment_prefix_whitespace: &str,
15255                ignore_indent: bool,
15256            ) -> Range<Point> {
15257                let indent_size = if ignore_indent {
15258                    0
15259                } else {
15260                    snapshot.indent_size_for_line(row).len
15261                };
15262
15263                let start = Point::new(row.0, indent_size);
15264
15265                let mut line_bytes = snapshot
15266                    .bytes_in_range(start..snapshot.max_point())
15267                    .flatten()
15268                    .copied();
15269
15270                // If this line currently begins with the line comment prefix, then record
15271                // the range containing the prefix.
15272                if line_bytes
15273                    .by_ref()
15274                    .take(comment_prefix.len())
15275                    .eq(comment_prefix.bytes())
15276                {
15277                    // Include any whitespace that matches the comment prefix.
15278                    let matching_whitespace_len = line_bytes
15279                        .zip(comment_prefix_whitespace.bytes())
15280                        .take_while(|(a, b)| a == b)
15281                        .count() as u32;
15282                    let end = Point::new(
15283                        start.row,
15284                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15285                    );
15286                    start..end
15287                } else {
15288                    start..start
15289                }
15290            }
15291
15292            fn comment_suffix_range(
15293                snapshot: &MultiBufferSnapshot,
15294                row: MultiBufferRow,
15295                comment_suffix: &str,
15296                comment_suffix_has_leading_space: bool,
15297            ) -> Range<Point> {
15298                let end = Point::new(row.0, snapshot.line_len(row));
15299                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15300
15301                let mut line_end_bytes = snapshot
15302                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15303                    .flatten()
15304                    .copied();
15305
15306                let leading_space_len = if suffix_start_column > 0
15307                    && line_end_bytes.next() == Some(b' ')
15308                    && comment_suffix_has_leading_space
15309                {
15310                    1
15311                } else {
15312                    0
15313                };
15314
15315                // If this line currently begins with the line comment prefix, then record
15316                // the range containing the prefix.
15317                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15318                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15319                    start..end
15320                } else {
15321                    end..end
15322                }
15323            }
15324
15325            // TODO: Handle selections that cross excerpts
15326            for selection in &mut selections {
15327                let start_column = snapshot
15328                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15329                    .len;
15330                let language = if let Some(language) =
15331                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15332                {
15333                    language
15334                } else {
15335                    continue;
15336                };
15337
15338                selection_edit_ranges.clear();
15339
15340                // If multiple selections contain a given row, avoid processing that
15341                // row more than once.
15342                let mut start_row = MultiBufferRow(selection.start.row);
15343                if last_toggled_row == Some(start_row) {
15344                    start_row = start_row.next_row();
15345                }
15346                let end_row =
15347                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15348                        MultiBufferRow(selection.end.row - 1)
15349                    } else {
15350                        MultiBufferRow(selection.end.row)
15351                    };
15352                last_toggled_row = Some(end_row);
15353
15354                if start_row > end_row {
15355                    continue;
15356                }
15357
15358                // If the language has line comments, toggle those.
15359                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15360
15361                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15362                if ignore_indent {
15363                    full_comment_prefixes = full_comment_prefixes
15364                        .into_iter()
15365                        .map(|s| Arc::from(s.trim_end()))
15366                        .collect();
15367                }
15368
15369                if !full_comment_prefixes.is_empty() {
15370                    let first_prefix = full_comment_prefixes
15371                        .first()
15372                        .expect("prefixes is non-empty");
15373                    let prefix_trimmed_lengths = full_comment_prefixes
15374                        .iter()
15375                        .map(|p| p.trim_end_matches(' ').len())
15376                        .collect::<SmallVec<[usize; 4]>>();
15377
15378                    let mut all_selection_lines_are_comments = true;
15379
15380                    for row in start_row.0..=end_row.0 {
15381                        let row = MultiBufferRow(row);
15382                        if start_row < end_row && snapshot.is_line_blank(row) {
15383                            continue;
15384                        }
15385
15386                        let prefix_range = full_comment_prefixes
15387                            .iter()
15388                            .zip(prefix_trimmed_lengths.iter().copied())
15389                            .map(|(prefix, trimmed_prefix_len)| {
15390                                comment_prefix_range(
15391                                    snapshot.deref(),
15392                                    row,
15393                                    &prefix[..trimmed_prefix_len],
15394                                    &prefix[trimmed_prefix_len..],
15395                                    ignore_indent,
15396                                )
15397                            })
15398                            .max_by_key(|range| range.end.column - range.start.column)
15399                            .expect("prefixes is non-empty");
15400
15401                        if prefix_range.is_empty() {
15402                            all_selection_lines_are_comments = false;
15403                        }
15404
15405                        selection_edit_ranges.push(prefix_range);
15406                    }
15407
15408                    if all_selection_lines_are_comments {
15409                        edits.extend(
15410                            selection_edit_ranges
15411                                .iter()
15412                                .cloned()
15413                                .map(|range| (range, empty_str.clone())),
15414                        );
15415                    } else {
15416                        let min_column = selection_edit_ranges
15417                            .iter()
15418                            .map(|range| range.start.column)
15419                            .min()
15420                            .unwrap_or(0);
15421                        edits.extend(selection_edit_ranges.iter().map(|range| {
15422                            let position = Point::new(range.start.row, min_column);
15423                            (position..position, first_prefix.clone())
15424                        }));
15425                    }
15426                } else if let Some(BlockCommentConfig {
15427                    start: full_comment_prefix,
15428                    end: comment_suffix,
15429                    ..
15430                }) = language.block_comment()
15431                {
15432                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15433                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15434                    let prefix_range = comment_prefix_range(
15435                        snapshot.deref(),
15436                        start_row,
15437                        comment_prefix,
15438                        comment_prefix_whitespace,
15439                        ignore_indent,
15440                    );
15441                    let suffix_range = comment_suffix_range(
15442                        snapshot.deref(),
15443                        end_row,
15444                        comment_suffix.trim_start_matches(' '),
15445                        comment_suffix.starts_with(' '),
15446                    );
15447
15448                    if prefix_range.is_empty() || suffix_range.is_empty() {
15449                        edits.push((
15450                            prefix_range.start..prefix_range.start,
15451                            full_comment_prefix.clone(),
15452                        ));
15453                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15454                        suffixes_inserted.push((end_row, comment_suffix.len()));
15455                    } else {
15456                        edits.push((prefix_range, empty_str.clone()));
15457                        edits.push((suffix_range, empty_str.clone()));
15458                    }
15459                } else {
15460                    continue;
15461                }
15462            }
15463
15464            drop(snapshot);
15465            this.buffer.update(cx, |buffer, cx| {
15466                buffer.edit(edits, None, cx);
15467            });
15468
15469            // Adjust selections so that they end before any comment suffixes that
15470            // were inserted.
15471            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15472            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15473            let snapshot = this.buffer.read(cx).read(cx);
15474            for selection in &mut selections {
15475                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15476                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15477                        Ordering::Less => {
15478                            suffixes_inserted.next();
15479                            continue;
15480                        }
15481                        Ordering::Greater => break,
15482                        Ordering::Equal => {
15483                            if selection.end.column == snapshot.line_len(row) {
15484                                if selection.is_empty() {
15485                                    selection.start.column -= suffix_len as u32;
15486                                }
15487                                selection.end.column -= suffix_len as u32;
15488                            }
15489                            break;
15490                        }
15491                    }
15492                }
15493            }
15494
15495            drop(snapshot);
15496            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15497
15498            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15499            let selections_on_single_row = selections.windows(2).all(|selections| {
15500                selections[0].start.row == selections[1].start.row
15501                    && selections[0].end.row == selections[1].end.row
15502                    && selections[0].start.row == selections[0].end.row
15503            });
15504            let selections_selecting = selections
15505                .iter()
15506                .any(|selection| selection.start != selection.end);
15507            let advance_downwards = action.advance_downwards
15508                && selections_on_single_row
15509                && !selections_selecting
15510                && !matches!(this.mode, EditorMode::SingleLine);
15511
15512            if advance_downwards {
15513                let snapshot = this.buffer.read(cx).snapshot(cx);
15514
15515                this.change_selections(Default::default(), window, cx, |s| {
15516                    s.move_cursors_with(|display_snapshot, display_point, _| {
15517                        let mut point = display_point.to_point(display_snapshot);
15518                        point.row += 1;
15519                        point = snapshot.clip_point(point, Bias::Left);
15520                        let display_point = point.to_display_point(display_snapshot);
15521                        let goal = SelectionGoal::HorizontalPosition(
15522                            display_snapshot
15523                                .x_for_display_point(display_point, text_layout_details)
15524                                .into(),
15525                        );
15526                        (display_point, goal)
15527                    })
15528                });
15529            }
15530        });
15531    }
15532
15533    pub fn select_enclosing_symbol(
15534        &mut self,
15535        _: &SelectEnclosingSymbol,
15536        window: &mut Window,
15537        cx: &mut Context<Self>,
15538    ) {
15539        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15540
15541        let buffer = self.buffer.read(cx).snapshot(cx);
15542        let old_selections = self
15543            .selections
15544            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15545            .into_boxed_slice();
15546
15547        fn update_selection(
15548            selection: &Selection<MultiBufferOffset>,
15549            buffer_snap: &MultiBufferSnapshot,
15550        ) -> Option<Selection<MultiBufferOffset>> {
15551            let cursor = selection.head();
15552            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15553            for symbol in symbols.iter().rev() {
15554                let start = symbol.range.start.to_offset(buffer_snap);
15555                let end = symbol.range.end.to_offset(buffer_snap);
15556                let new_range = start..end;
15557                if start < selection.start || end > selection.end {
15558                    return Some(Selection {
15559                        id: selection.id,
15560                        start: new_range.start,
15561                        end: new_range.end,
15562                        goal: SelectionGoal::None,
15563                        reversed: selection.reversed,
15564                    });
15565                }
15566            }
15567            None
15568        }
15569
15570        let mut selected_larger_symbol = false;
15571        let new_selections = old_selections
15572            .iter()
15573            .map(|selection| match update_selection(selection, &buffer) {
15574                Some(new_selection) => {
15575                    if new_selection.range() != selection.range() {
15576                        selected_larger_symbol = true;
15577                    }
15578                    new_selection
15579                }
15580                None => selection.clone(),
15581            })
15582            .collect::<Vec<_>>();
15583
15584        if selected_larger_symbol {
15585            self.change_selections(Default::default(), window, cx, |s| {
15586                s.select(new_selections);
15587            });
15588        }
15589    }
15590
15591    pub fn select_larger_syntax_node(
15592        &mut self,
15593        _: &SelectLargerSyntaxNode,
15594        window: &mut Window,
15595        cx: &mut Context<Self>,
15596    ) {
15597        let Some(visible_row_count) = self.visible_row_count() else {
15598            return;
15599        };
15600        let old_selections: Box<[_]> = self
15601            .selections
15602            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15603            .into();
15604        if old_selections.is_empty() {
15605            return;
15606        }
15607
15608        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15609
15610        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15611        let buffer = self.buffer.read(cx).snapshot(cx);
15612
15613        let mut selected_larger_node = false;
15614        let mut new_selections = old_selections
15615            .iter()
15616            .map(|selection| {
15617                let old_range = selection.start..selection.end;
15618
15619                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15620                    // manually select word at selection
15621                    if ["string_content", "inline"].contains(&node.kind()) {
15622                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15623                        // ignore if word is already selected
15624                        if !word_range.is_empty() && old_range != word_range {
15625                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15626                            // only select word if start and end point belongs to same word
15627                            if word_range == last_word_range {
15628                                selected_larger_node = true;
15629                                return Selection {
15630                                    id: selection.id,
15631                                    start: word_range.start,
15632                                    end: word_range.end,
15633                                    goal: SelectionGoal::None,
15634                                    reversed: selection.reversed,
15635                                };
15636                            }
15637                        }
15638                    }
15639                }
15640
15641                let mut new_range = old_range.clone();
15642                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15643                    new_range = range;
15644                    if !node.is_named() {
15645                        continue;
15646                    }
15647                    if !display_map.intersects_fold(new_range.start)
15648                        && !display_map.intersects_fold(new_range.end)
15649                    {
15650                        break;
15651                    }
15652                }
15653
15654                selected_larger_node |= new_range != old_range;
15655                Selection {
15656                    id: selection.id,
15657                    start: new_range.start,
15658                    end: new_range.end,
15659                    goal: SelectionGoal::None,
15660                    reversed: selection.reversed,
15661                }
15662            })
15663            .collect::<Vec<_>>();
15664
15665        if !selected_larger_node {
15666            return; // don't put this call in the history
15667        }
15668
15669        // scroll based on transformation done to the last selection created by the user
15670        let (last_old, last_new) = old_selections
15671            .last()
15672            .zip(new_selections.last().cloned())
15673            .expect("old_selections isn't empty");
15674
15675        // revert selection
15676        let is_selection_reversed = {
15677            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15678            new_selections.last_mut().expect("checked above").reversed =
15679                should_newest_selection_be_reversed;
15680            should_newest_selection_be_reversed
15681        };
15682
15683        if selected_larger_node {
15684            self.select_syntax_node_history.disable_clearing = true;
15685            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15686                s.select(new_selections.clone());
15687            });
15688            self.select_syntax_node_history.disable_clearing = false;
15689        }
15690
15691        let start_row = last_new.start.to_display_point(&display_map).row().0;
15692        let end_row = last_new.end.to_display_point(&display_map).row().0;
15693        let selection_height = end_row - start_row + 1;
15694        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15695
15696        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15697        let scroll_behavior = if fits_on_the_screen {
15698            self.request_autoscroll(Autoscroll::fit(), cx);
15699            SelectSyntaxNodeScrollBehavior::FitSelection
15700        } else if is_selection_reversed {
15701            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15702            SelectSyntaxNodeScrollBehavior::CursorTop
15703        } else {
15704            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15705            SelectSyntaxNodeScrollBehavior::CursorBottom
15706        };
15707
15708        self.select_syntax_node_history.push((
15709            old_selections,
15710            scroll_behavior,
15711            is_selection_reversed,
15712        ));
15713    }
15714
15715    pub fn select_smaller_syntax_node(
15716        &mut self,
15717        _: &SelectSmallerSyntaxNode,
15718        window: &mut Window,
15719        cx: &mut Context<Self>,
15720    ) {
15721        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15722
15723        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15724            self.select_syntax_node_history.pop()
15725        {
15726            if let Some(selection) = selections.last_mut() {
15727                selection.reversed = is_selection_reversed;
15728            }
15729
15730            self.select_syntax_node_history.disable_clearing = true;
15731            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15732                s.select(selections.to_vec());
15733            });
15734            self.select_syntax_node_history.disable_clearing = false;
15735
15736            match scroll_behavior {
15737                SelectSyntaxNodeScrollBehavior::CursorTop => {
15738                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15739                }
15740                SelectSyntaxNodeScrollBehavior::FitSelection => {
15741                    self.request_autoscroll(Autoscroll::fit(), cx);
15742                }
15743                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15744                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15745                }
15746            }
15747        }
15748    }
15749
15750    pub fn unwrap_syntax_node(
15751        &mut self,
15752        _: &UnwrapSyntaxNode,
15753        window: &mut Window,
15754        cx: &mut Context<Self>,
15755    ) {
15756        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15757
15758        let buffer = self.buffer.read(cx).snapshot(cx);
15759        let selections = self
15760            .selections
15761            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15762            .into_iter()
15763            // subtracting the offset requires sorting
15764            .sorted_by_key(|i| i.start);
15765
15766        let full_edits = selections
15767            .into_iter()
15768            .filter_map(|selection| {
15769                let child = if selection.is_empty()
15770                    && let Some((_, ancestor_range)) =
15771                        buffer.syntax_ancestor(selection.start..selection.end)
15772                {
15773                    ancestor_range
15774                } else {
15775                    selection.range()
15776                };
15777
15778                let mut parent = child.clone();
15779                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15780                    parent = ancestor_range;
15781                    if parent.start < child.start || parent.end > child.end {
15782                        break;
15783                    }
15784                }
15785
15786                if parent == child {
15787                    return None;
15788                }
15789                let text = buffer.text_for_range(child).collect::<String>();
15790                Some((selection.id, parent, text))
15791            })
15792            .collect::<Vec<_>>();
15793        if full_edits.is_empty() {
15794            return;
15795        }
15796
15797        self.transact(window, cx, |this, window, cx| {
15798            this.buffer.update(cx, |buffer, cx| {
15799                buffer.edit(
15800                    full_edits
15801                        .iter()
15802                        .map(|(_, p, t)| (p.clone(), t.clone()))
15803                        .collect::<Vec<_>>(),
15804                    None,
15805                    cx,
15806                );
15807            });
15808            this.change_selections(Default::default(), window, cx, |s| {
15809                let mut offset = 0;
15810                let mut selections = vec![];
15811                for (id, parent, text) in full_edits {
15812                    let start = parent.start - offset;
15813                    offset += (parent.end - parent.start) - text.len();
15814                    selections.push(Selection {
15815                        id,
15816                        start,
15817                        end: start + text.len(),
15818                        reversed: false,
15819                        goal: Default::default(),
15820                    });
15821                }
15822                s.select(selections);
15823            });
15824        });
15825    }
15826
15827    pub fn select_next_syntax_node(
15828        &mut self,
15829        _: &SelectNextSyntaxNode,
15830        window: &mut Window,
15831        cx: &mut Context<Self>,
15832    ) {
15833        let old_selections: Box<[_]> = self
15834            .selections
15835            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15836            .into();
15837        if old_selections.is_empty() {
15838            return;
15839        }
15840
15841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15842
15843        let buffer = self.buffer.read(cx).snapshot(cx);
15844        let mut selected_sibling = false;
15845
15846        let new_selections = old_selections
15847            .iter()
15848            .map(|selection| {
15849                let old_range = selection.start..selection.end;
15850
15851                let old_range =
15852                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15853                let excerpt = buffer.excerpt_containing(old_range.clone());
15854
15855                if let Some(mut excerpt) = excerpt
15856                    && let Some(node) = excerpt
15857                        .buffer()
15858                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
15859                {
15860                    let new_range = excerpt.map_range_from_buffer(
15861                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15862                    );
15863                    selected_sibling = true;
15864                    Selection {
15865                        id: selection.id,
15866                        start: new_range.start,
15867                        end: new_range.end,
15868                        goal: SelectionGoal::None,
15869                        reversed: selection.reversed,
15870                    }
15871                } else {
15872                    selection.clone()
15873                }
15874            })
15875            .collect::<Vec<_>>();
15876
15877        if selected_sibling {
15878            self.change_selections(
15879                SelectionEffects::scroll(Autoscroll::fit()),
15880                window,
15881                cx,
15882                |s| {
15883                    s.select(new_selections);
15884                },
15885            );
15886        }
15887    }
15888
15889    pub fn select_prev_syntax_node(
15890        &mut self,
15891        _: &SelectPreviousSyntaxNode,
15892        window: &mut Window,
15893        cx: &mut Context<Self>,
15894    ) {
15895        let old_selections: Box<[_]> = self
15896            .selections
15897            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15898            .into();
15899        if old_selections.is_empty() {
15900            return;
15901        }
15902
15903        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15904
15905        let buffer = self.buffer.read(cx).snapshot(cx);
15906        let mut selected_sibling = false;
15907
15908        let new_selections = old_selections
15909            .iter()
15910            .map(|selection| {
15911                let old_range = selection.start..selection.end;
15912                let old_range =
15913                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15914                let excerpt = buffer.excerpt_containing(old_range.clone());
15915
15916                if let Some(mut excerpt) = excerpt
15917                    && let Some(node) = excerpt
15918                        .buffer()
15919                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
15920                {
15921                    let new_range = excerpt.map_range_from_buffer(
15922                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15923                    );
15924                    selected_sibling = true;
15925                    Selection {
15926                        id: selection.id,
15927                        start: new_range.start,
15928                        end: new_range.end,
15929                        goal: SelectionGoal::None,
15930                        reversed: selection.reversed,
15931                    }
15932                } else {
15933                    selection.clone()
15934                }
15935            })
15936            .collect::<Vec<_>>();
15937
15938        if selected_sibling {
15939            self.change_selections(
15940                SelectionEffects::scroll(Autoscroll::fit()),
15941                window,
15942                cx,
15943                |s| {
15944                    s.select(new_selections);
15945                },
15946            );
15947        }
15948    }
15949
15950    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15951        if !EditorSettings::get_global(cx).gutter.runnables {
15952            self.clear_tasks();
15953            return Task::ready(());
15954        }
15955        let project = self.project().map(Entity::downgrade);
15956        let task_sources = self.lsp_task_sources(cx);
15957        let multi_buffer = self.buffer.downgrade();
15958        cx.spawn_in(window, async move |editor, cx| {
15959            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15960            let Some(project) = project.and_then(|p| p.upgrade()) else {
15961                return;
15962            };
15963            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15964                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15965            }) else {
15966                return;
15967            };
15968
15969            let hide_runnables = project
15970                .update(cx, |project, _| project.is_via_collab())
15971                .unwrap_or(true);
15972            if hide_runnables {
15973                return;
15974            }
15975            let new_rows =
15976                cx.background_spawn({
15977                    let snapshot = display_snapshot.clone();
15978                    async move {
15979                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15980                    }
15981                })
15982                    .await;
15983            let Ok(lsp_tasks) =
15984                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15985            else {
15986                return;
15987            };
15988            let lsp_tasks = lsp_tasks.await;
15989
15990            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15991                lsp_tasks
15992                    .into_iter()
15993                    .flat_map(|(kind, tasks)| {
15994                        tasks.into_iter().filter_map(move |(location, task)| {
15995                            Some((kind.clone(), location?, task))
15996                        })
15997                    })
15998                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15999                        let buffer = location.target.buffer;
16000                        let buffer_snapshot = buffer.read(cx).snapshot();
16001                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16002                            |(excerpt_id, snapshot, _)| {
16003                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16004                                    display_snapshot
16005                                        .buffer_snapshot()
16006                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16007                                } else {
16008                                    None
16009                                }
16010                            },
16011                        );
16012                        if let Some(offset) = offset {
16013                            let task_buffer_range =
16014                                location.target.range.to_point(&buffer_snapshot);
16015                            let context_buffer_range =
16016                                task_buffer_range.to_offset(&buffer_snapshot);
16017                            let context_range = BufferOffset(context_buffer_range.start)
16018                                ..BufferOffset(context_buffer_range.end);
16019
16020                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16021                                .or_insert_with(|| RunnableTasks {
16022                                    templates: Vec::new(),
16023                                    offset,
16024                                    column: task_buffer_range.start.column,
16025                                    extra_variables: HashMap::default(),
16026                                    context_range,
16027                                })
16028                                .templates
16029                                .push((kind, task.original_task().clone()));
16030                        }
16031
16032                        acc
16033                    })
16034            }) else {
16035                return;
16036            };
16037
16038            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16039                buffer.language_settings(cx).tasks.prefer_lsp
16040            }) else {
16041                return;
16042            };
16043
16044            let rows = Self::runnable_rows(
16045                project,
16046                display_snapshot,
16047                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16048                new_rows,
16049                cx.clone(),
16050            )
16051            .await;
16052            editor
16053                .update(cx, |editor, _| {
16054                    editor.clear_tasks();
16055                    for (key, mut value) in rows {
16056                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16057                            value.templates.extend(lsp_tasks.templates);
16058                        }
16059
16060                        editor.insert_tasks(key, value);
16061                    }
16062                    for (key, value) in lsp_tasks_by_rows {
16063                        editor.insert_tasks(key, value);
16064                    }
16065                })
16066                .ok();
16067        })
16068    }
16069    fn fetch_runnable_ranges(
16070        snapshot: &DisplaySnapshot,
16071        range: Range<Anchor>,
16072    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16073        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16074    }
16075
16076    fn runnable_rows(
16077        project: Entity<Project>,
16078        snapshot: DisplaySnapshot,
16079        prefer_lsp: bool,
16080        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16081        cx: AsyncWindowContext,
16082    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16083        cx.spawn(async move |cx| {
16084            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16085            for (run_range, mut runnable) in runnable_ranges {
16086                let Some(tasks) = cx
16087                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16088                    .ok()
16089                else {
16090                    continue;
16091                };
16092                let mut tasks = tasks.await;
16093
16094                if prefer_lsp {
16095                    tasks.retain(|(task_kind, _)| {
16096                        !matches!(task_kind, TaskSourceKind::Language { .. })
16097                    });
16098                }
16099                if tasks.is_empty() {
16100                    continue;
16101                }
16102
16103                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16104                let Some(row) = snapshot
16105                    .buffer_snapshot()
16106                    .buffer_line_for_row(MultiBufferRow(point.row))
16107                    .map(|(_, range)| range.start.row)
16108                else {
16109                    continue;
16110                };
16111
16112                let context_range =
16113                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16114                runnable_rows.push((
16115                    (runnable.buffer_id, row),
16116                    RunnableTasks {
16117                        templates: tasks,
16118                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16119                        context_range,
16120                        column: point.column,
16121                        extra_variables: runnable.extra_captures,
16122                    },
16123                ));
16124            }
16125            runnable_rows
16126        })
16127    }
16128
16129    fn templates_with_tags(
16130        project: &Entity<Project>,
16131        runnable: &mut Runnable,
16132        cx: &mut App,
16133    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16134        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16135            let (worktree_id, file) = project
16136                .buffer_for_id(runnable.buffer, cx)
16137                .and_then(|buffer| buffer.read(cx).file())
16138                .map(|file| (file.worktree_id(cx), file.clone()))
16139                .unzip();
16140
16141            (
16142                project.task_store().read(cx).task_inventory().cloned(),
16143                worktree_id,
16144                file,
16145            )
16146        });
16147
16148        let tags = mem::take(&mut runnable.tags);
16149        let language = runnable.language.clone();
16150        cx.spawn(async move |cx| {
16151            let mut templates_with_tags = Vec::new();
16152            if let Some(inventory) = inventory {
16153                for RunnableTag(tag) in tags {
16154                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16155                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16156                    }) else {
16157                        return templates_with_tags;
16158                    };
16159                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16160                        move |(_, template)| {
16161                            template.tags.iter().any(|source_tag| source_tag == &tag)
16162                        },
16163                    ));
16164                }
16165            }
16166            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16167
16168            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16169                // Strongest source wins; if we have worktree tag binding, prefer that to
16170                // global and language bindings;
16171                // if we have a global binding, prefer that to language binding.
16172                let first_mismatch = templates_with_tags
16173                    .iter()
16174                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16175                if let Some(index) = first_mismatch {
16176                    templates_with_tags.truncate(index);
16177                }
16178            }
16179
16180            templates_with_tags
16181        })
16182    }
16183
16184    pub fn move_to_enclosing_bracket(
16185        &mut self,
16186        _: &MoveToEnclosingBracket,
16187        window: &mut Window,
16188        cx: &mut Context<Self>,
16189    ) {
16190        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16191        self.change_selections(Default::default(), window, cx, |s| {
16192            s.move_offsets_with(|snapshot, selection| {
16193                let Some(enclosing_bracket_ranges) =
16194                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16195                else {
16196                    return;
16197                };
16198
16199                let mut best_length = usize::MAX;
16200                let mut best_inside = false;
16201                let mut best_in_bracket_range = false;
16202                let mut best_destination = None;
16203                for (open, close) in enclosing_bracket_ranges {
16204                    let close = close.to_inclusive();
16205                    let length = *close.end() - open.start;
16206                    let inside = selection.start >= open.end && selection.end <= *close.start();
16207                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16208                        || close.contains(&selection.head());
16209
16210                    // If best is next to a bracket and current isn't, skip
16211                    if !in_bracket_range && best_in_bracket_range {
16212                        continue;
16213                    }
16214
16215                    // Prefer smaller lengths unless best is inside and current isn't
16216                    if length > best_length && (best_inside || !inside) {
16217                        continue;
16218                    }
16219
16220                    best_length = length;
16221                    best_inside = inside;
16222                    best_in_bracket_range = in_bracket_range;
16223                    best_destination = Some(
16224                        if close.contains(&selection.start) && close.contains(&selection.end) {
16225                            if inside { open.end } else { open.start }
16226                        } else if inside {
16227                            *close.start()
16228                        } else {
16229                            *close.end()
16230                        },
16231                    );
16232                }
16233
16234                if let Some(destination) = best_destination {
16235                    selection.collapse_to(destination, SelectionGoal::None);
16236                }
16237            })
16238        });
16239    }
16240
16241    pub fn undo_selection(
16242        &mut self,
16243        _: &UndoSelection,
16244        window: &mut Window,
16245        cx: &mut Context<Self>,
16246    ) {
16247        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16248        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16249            self.selection_history.mode = SelectionHistoryMode::Undoing;
16250            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16251                this.end_selection(window, cx);
16252                this.change_selections(
16253                    SelectionEffects::scroll(Autoscroll::newest()),
16254                    window,
16255                    cx,
16256                    |s| s.select_anchors(entry.selections.to_vec()),
16257                );
16258            });
16259            self.selection_history.mode = SelectionHistoryMode::Normal;
16260
16261            self.select_next_state = entry.select_next_state;
16262            self.select_prev_state = entry.select_prev_state;
16263            self.add_selections_state = entry.add_selections_state;
16264        }
16265    }
16266
16267    pub fn redo_selection(
16268        &mut self,
16269        _: &RedoSelection,
16270        window: &mut Window,
16271        cx: &mut Context<Self>,
16272    ) {
16273        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16274        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16275            self.selection_history.mode = SelectionHistoryMode::Redoing;
16276            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16277                this.end_selection(window, cx);
16278                this.change_selections(
16279                    SelectionEffects::scroll(Autoscroll::newest()),
16280                    window,
16281                    cx,
16282                    |s| s.select_anchors(entry.selections.to_vec()),
16283                );
16284            });
16285            self.selection_history.mode = SelectionHistoryMode::Normal;
16286
16287            self.select_next_state = entry.select_next_state;
16288            self.select_prev_state = entry.select_prev_state;
16289            self.add_selections_state = entry.add_selections_state;
16290        }
16291    }
16292
16293    pub fn expand_excerpts(
16294        &mut self,
16295        action: &ExpandExcerpts,
16296        _: &mut Window,
16297        cx: &mut Context<Self>,
16298    ) {
16299        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16300    }
16301
16302    pub fn expand_excerpts_down(
16303        &mut self,
16304        action: &ExpandExcerptsDown,
16305        _: &mut Window,
16306        cx: &mut Context<Self>,
16307    ) {
16308        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16309    }
16310
16311    pub fn expand_excerpts_up(
16312        &mut self,
16313        action: &ExpandExcerptsUp,
16314        _: &mut Window,
16315        cx: &mut Context<Self>,
16316    ) {
16317        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16318    }
16319
16320    pub fn expand_excerpts_for_direction(
16321        &mut self,
16322        lines: u32,
16323        direction: ExpandExcerptDirection,
16324
16325        cx: &mut Context<Self>,
16326    ) {
16327        let selections = self.selections.disjoint_anchors_arc();
16328
16329        let lines = if lines == 0 {
16330            EditorSettings::get_global(cx).expand_excerpt_lines
16331        } else {
16332            lines
16333        };
16334
16335        self.buffer.update(cx, |buffer, cx| {
16336            let snapshot = buffer.snapshot(cx);
16337            let mut excerpt_ids = selections
16338                .iter()
16339                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16340                .collect::<Vec<_>>();
16341            excerpt_ids.sort();
16342            excerpt_ids.dedup();
16343            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16344        })
16345    }
16346
16347    pub fn expand_excerpt(
16348        &mut self,
16349        excerpt: ExcerptId,
16350        direction: ExpandExcerptDirection,
16351        window: &mut Window,
16352        cx: &mut Context<Self>,
16353    ) {
16354        let current_scroll_position = self.scroll_position(cx);
16355        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16356        let mut scroll = None;
16357
16358        if direction == ExpandExcerptDirection::Down {
16359            let multi_buffer = self.buffer.read(cx);
16360            let snapshot = multi_buffer.snapshot(cx);
16361            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16362                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16363                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16364            {
16365                let buffer_snapshot = buffer.read(cx).snapshot();
16366                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16367                let last_row = buffer_snapshot.max_point().row;
16368                let lines_below = last_row.saturating_sub(excerpt_end_row);
16369                if lines_below >= lines_to_expand {
16370                    scroll = Some(
16371                        current_scroll_position
16372                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16373                    );
16374                }
16375            }
16376        }
16377        if direction == ExpandExcerptDirection::Up
16378            && self
16379                .buffer
16380                .read(cx)
16381                .snapshot(cx)
16382                .excerpt_before(excerpt)
16383                .is_none()
16384        {
16385            scroll = Some(current_scroll_position);
16386        }
16387
16388        self.buffer.update(cx, |buffer, cx| {
16389            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16390        });
16391
16392        if let Some(new_scroll_position) = scroll {
16393            self.set_scroll_position(new_scroll_position, window, cx);
16394        }
16395    }
16396
16397    pub fn go_to_singleton_buffer_point(
16398        &mut self,
16399        point: Point,
16400        window: &mut Window,
16401        cx: &mut Context<Self>,
16402    ) {
16403        self.go_to_singleton_buffer_range(point..point, window, cx);
16404    }
16405
16406    pub fn go_to_singleton_buffer_range(
16407        &mut self,
16408        range: Range<Point>,
16409        window: &mut Window,
16410        cx: &mut Context<Self>,
16411    ) {
16412        let multibuffer = self.buffer().read(cx);
16413        let Some(buffer) = multibuffer.as_singleton() else {
16414            return;
16415        };
16416        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16417            return;
16418        };
16419        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16420            return;
16421        };
16422        self.change_selections(
16423            SelectionEffects::default().nav_history(true),
16424            window,
16425            cx,
16426            |s| s.select_anchor_ranges([start..end]),
16427        );
16428    }
16429
16430    pub fn go_to_diagnostic(
16431        &mut self,
16432        action: &GoToDiagnostic,
16433        window: &mut Window,
16434        cx: &mut Context<Self>,
16435    ) {
16436        if !self.diagnostics_enabled() {
16437            return;
16438        }
16439        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16440        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16441    }
16442
16443    pub fn go_to_prev_diagnostic(
16444        &mut self,
16445        action: &GoToPreviousDiagnostic,
16446        window: &mut Window,
16447        cx: &mut Context<Self>,
16448    ) {
16449        if !self.diagnostics_enabled() {
16450            return;
16451        }
16452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16453        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16454    }
16455
16456    pub fn go_to_diagnostic_impl(
16457        &mut self,
16458        direction: Direction,
16459        severity: GoToDiagnosticSeverityFilter,
16460        window: &mut Window,
16461        cx: &mut Context<Self>,
16462    ) {
16463        let buffer = self.buffer.read(cx).snapshot(cx);
16464        let selection = self
16465            .selections
16466            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16467
16468        let mut active_group_id = None;
16469        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16470            && active_group.active_range.start.to_offset(&buffer) == selection.start
16471        {
16472            active_group_id = Some(active_group.group_id);
16473        }
16474
16475        fn filtered<'a>(
16476            severity: GoToDiagnosticSeverityFilter,
16477            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16478        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16479            diagnostics
16480                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16481                .filter(|entry| entry.range.start != entry.range.end)
16482                .filter(|entry| !entry.diagnostic.is_unnecessary)
16483        }
16484
16485        let before = filtered(
16486            severity,
16487            buffer
16488                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16489                .filter(|entry| entry.range.start <= selection.start),
16490        );
16491        let after = filtered(
16492            severity,
16493            buffer
16494                .diagnostics_in_range(selection.start..buffer.len())
16495                .filter(|entry| entry.range.start >= selection.start),
16496        );
16497
16498        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16499        if direction == Direction::Prev {
16500            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16501            {
16502                for diagnostic in prev_diagnostics.into_iter().rev() {
16503                    if diagnostic.range.start != selection.start
16504                        || active_group_id
16505                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16506                    {
16507                        found = Some(diagnostic);
16508                        break 'outer;
16509                    }
16510                }
16511            }
16512        } else {
16513            for diagnostic in after.chain(before) {
16514                if diagnostic.range.start != selection.start
16515                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16516                {
16517                    found = Some(diagnostic);
16518                    break;
16519                }
16520            }
16521        }
16522        let Some(next_diagnostic) = found else {
16523            return;
16524        };
16525
16526        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16527        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16528            return;
16529        };
16530        let snapshot = self.snapshot(window, cx);
16531        if snapshot.intersects_fold(next_diagnostic.range.start) {
16532            self.unfold_ranges(
16533                std::slice::from_ref(&next_diagnostic.range),
16534                true,
16535                false,
16536                cx,
16537            );
16538        }
16539        self.change_selections(Default::default(), window, cx, |s| {
16540            s.select_ranges(vec![
16541                next_diagnostic.range.start..next_diagnostic.range.start,
16542            ])
16543        });
16544        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16545        self.refresh_edit_prediction(false, true, window, cx);
16546    }
16547
16548    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16549        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16550        let snapshot = self.snapshot(window, cx);
16551        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16552        self.go_to_hunk_before_or_after_position(
16553            &snapshot,
16554            selection.head(),
16555            Direction::Next,
16556            window,
16557            cx,
16558        );
16559    }
16560
16561    pub fn go_to_hunk_before_or_after_position(
16562        &mut self,
16563        snapshot: &EditorSnapshot,
16564        position: Point,
16565        direction: Direction,
16566        window: &mut Window,
16567        cx: &mut Context<Editor>,
16568    ) {
16569        let row = if direction == Direction::Next {
16570            self.hunk_after_position(snapshot, position)
16571                .map(|hunk| hunk.row_range.start)
16572        } else {
16573            self.hunk_before_position(snapshot, position)
16574        };
16575
16576        if let Some(row) = row {
16577            let destination = Point::new(row.0, 0);
16578            let autoscroll = Autoscroll::center();
16579
16580            self.unfold_ranges(&[destination..destination], false, false, cx);
16581            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16582                s.select_ranges([destination..destination]);
16583            });
16584        }
16585    }
16586
16587    fn hunk_after_position(
16588        &mut self,
16589        snapshot: &EditorSnapshot,
16590        position: Point,
16591    ) -> Option<MultiBufferDiffHunk> {
16592        snapshot
16593            .buffer_snapshot()
16594            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16595            .find(|hunk| hunk.row_range.start.0 > position.row)
16596            .or_else(|| {
16597                snapshot
16598                    .buffer_snapshot()
16599                    .diff_hunks_in_range(Point::zero()..position)
16600                    .find(|hunk| hunk.row_range.end.0 < position.row)
16601            })
16602    }
16603
16604    fn go_to_prev_hunk(
16605        &mut self,
16606        _: &GoToPreviousHunk,
16607        window: &mut Window,
16608        cx: &mut Context<Self>,
16609    ) {
16610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16611        let snapshot = self.snapshot(window, cx);
16612        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16613        self.go_to_hunk_before_or_after_position(
16614            &snapshot,
16615            selection.head(),
16616            Direction::Prev,
16617            window,
16618            cx,
16619        );
16620    }
16621
16622    fn hunk_before_position(
16623        &mut self,
16624        snapshot: &EditorSnapshot,
16625        position: Point,
16626    ) -> Option<MultiBufferRow> {
16627        snapshot
16628            .buffer_snapshot()
16629            .diff_hunk_before(position)
16630            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16631    }
16632
16633    fn go_to_next_change(
16634        &mut self,
16635        _: &GoToNextChange,
16636        window: &mut Window,
16637        cx: &mut Context<Self>,
16638    ) {
16639        if let Some(selections) = self
16640            .change_list
16641            .next_change(1, Direction::Next)
16642            .map(|s| s.to_vec())
16643        {
16644            self.change_selections(Default::default(), window, cx, |s| {
16645                let map = s.display_snapshot();
16646                s.select_display_ranges(selections.iter().map(|a| {
16647                    let point = a.to_display_point(&map);
16648                    point..point
16649                }))
16650            })
16651        }
16652    }
16653
16654    fn go_to_previous_change(
16655        &mut self,
16656        _: &GoToPreviousChange,
16657        window: &mut Window,
16658        cx: &mut Context<Self>,
16659    ) {
16660        if let Some(selections) = self
16661            .change_list
16662            .next_change(1, Direction::Prev)
16663            .map(|s| s.to_vec())
16664        {
16665            self.change_selections(Default::default(), window, cx, |s| {
16666                let map = s.display_snapshot();
16667                s.select_display_ranges(selections.iter().map(|a| {
16668                    let point = a.to_display_point(&map);
16669                    point..point
16670                }))
16671            })
16672        }
16673    }
16674
16675    pub fn go_to_next_document_highlight(
16676        &mut self,
16677        _: &GoToNextDocumentHighlight,
16678        window: &mut Window,
16679        cx: &mut Context<Self>,
16680    ) {
16681        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16682    }
16683
16684    pub fn go_to_prev_document_highlight(
16685        &mut self,
16686        _: &GoToPreviousDocumentHighlight,
16687        window: &mut Window,
16688        cx: &mut Context<Self>,
16689    ) {
16690        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16691    }
16692
16693    pub fn go_to_document_highlight_before_or_after_position(
16694        &mut self,
16695        direction: Direction,
16696        window: &mut Window,
16697        cx: &mut Context<Editor>,
16698    ) {
16699        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16700        let snapshot = self.snapshot(window, cx);
16701        let buffer = &snapshot.buffer_snapshot();
16702        let position = self
16703            .selections
16704            .newest::<Point>(&snapshot.display_snapshot)
16705            .head();
16706        let anchor_position = buffer.anchor_after(position);
16707
16708        // Get all document highlights (both read and write)
16709        let mut all_highlights = Vec::new();
16710
16711        if let Some((_, read_highlights)) = self
16712            .background_highlights
16713            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16714        {
16715            all_highlights.extend(read_highlights.iter());
16716        }
16717
16718        if let Some((_, write_highlights)) = self
16719            .background_highlights
16720            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16721        {
16722            all_highlights.extend(write_highlights.iter());
16723        }
16724
16725        if all_highlights.is_empty() {
16726            return;
16727        }
16728
16729        // Sort highlights by position
16730        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16731
16732        let target_highlight = match direction {
16733            Direction::Next => {
16734                // Find the first highlight after the current position
16735                all_highlights
16736                    .iter()
16737                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16738            }
16739            Direction::Prev => {
16740                // Find the last highlight before the current position
16741                all_highlights
16742                    .iter()
16743                    .rev()
16744                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16745            }
16746        };
16747
16748        if let Some(highlight) = target_highlight {
16749            let destination = highlight.start.to_point(buffer);
16750            let autoscroll = Autoscroll::center();
16751
16752            self.unfold_ranges(&[destination..destination], false, false, cx);
16753            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16754                s.select_ranges([destination..destination]);
16755            });
16756        }
16757    }
16758
16759    fn go_to_line<T: 'static>(
16760        &mut self,
16761        position: Anchor,
16762        highlight_color: Option<Hsla>,
16763        window: &mut Window,
16764        cx: &mut Context<Self>,
16765    ) {
16766        let snapshot = self.snapshot(window, cx).display_snapshot;
16767        let position = position.to_point(&snapshot.buffer_snapshot());
16768        let start = snapshot
16769            .buffer_snapshot()
16770            .clip_point(Point::new(position.row, 0), Bias::Left);
16771        let end = start + Point::new(1, 0);
16772        let start = snapshot.buffer_snapshot().anchor_before(start);
16773        let end = snapshot.buffer_snapshot().anchor_before(end);
16774
16775        self.highlight_rows::<T>(
16776            start..end,
16777            highlight_color
16778                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16779            Default::default(),
16780            cx,
16781        );
16782
16783        if self.buffer.read(cx).is_singleton() {
16784            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16785        }
16786    }
16787
16788    pub fn go_to_definition(
16789        &mut self,
16790        _: &GoToDefinition,
16791        window: &mut Window,
16792        cx: &mut Context<Self>,
16793    ) -> Task<Result<Navigated>> {
16794        let definition =
16795            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16796        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16797        cx.spawn_in(window, async move |editor, cx| {
16798            if definition.await? == Navigated::Yes {
16799                return Ok(Navigated::Yes);
16800            }
16801            match fallback_strategy {
16802                GoToDefinitionFallback::None => Ok(Navigated::No),
16803                GoToDefinitionFallback::FindAllReferences => {
16804                    match editor.update_in(cx, |editor, window, cx| {
16805                        editor.find_all_references(&FindAllReferences, window, cx)
16806                    })? {
16807                        Some(references) => references.await,
16808                        None => Ok(Navigated::No),
16809                    }
16810                }
16811            }
16812        })
16813    }
16814
16815    pub fn go_to_declaration(
16816        &mut self,
16817        _: &GoToDeclaration,
16818        window: &mut Window,
16819        cx: &mut Context<Self>,
16820    ) -> Task<Result<Navigated>> {
16821        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16822    }
16823
16824    pub fn go_to_declaration_split(
16825        &mut self,
16826        _: &GoToDeclaration,
16827        window: &mut Window,
16828        cx: &mut Context<Self>,
16829    ) -> Task<Result<Navigated>> {
16830        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16831    }
16832
16833    pub fn go_to_implementation(
16834        &mut self,
16835        _: &GoToImplementation,
16836        window: &mut Window,
16837        cx: &mut Context<Self>,
16838    ) -> Task<Result<Navigated>> {
16839        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16840    }
16841
16842    pub fn go_to_implementation_split(
16843        &mut self,
16844        _: &GoToImplementationSplit,
16845        window: &mut Window,
16846        cx: &mut Context<Self>,
16847    ) -> Task<Result<Navigated>> {
16848        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16849    }
16850
16851    pub fn go_to_type_definition(
16852        &mut self,
16853        _: &GoToTypeDefinition,
16854        window: &mut Window,
16855        cx: &mut Context<Self>,
16856    ) -> Task<Result<Navigated>> {
16857        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16858    }
16859
16860    pub fn go_to_definition_split(
16861        &mut self,
16862        _: &GoToDefinitionSplit,
16863        window: &mut Window,
16864        cx: &mut Context<Self>,
16865    ) -> Task<Result<Navigated>> {
16866        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16867    }
16868
16869    pub fn go_to_type_definition_split(
16870        &mut self,
16871        _: &GoToTypeDefinitionSplit,
16872        window: &mut Window,
16873        cx: &mut Context<Self>,
16874    ) -> Task<Result<Navigated>> {
16875        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16876    }
16877
16878    fn go_to_definition_of_kind(
16879        &mut self,
16880        kind: GotoDefinitionKind,
16881        split: bool,
16882        window: &mut Window,
16883        cx: &mut Context<Self>,
16884    ) -> Task<Result<Navigated>> {
16885        let Some(provider) = self.semantics_provider.clone() else {
16886            return Task::ready(Ok(Navigated::No));
16887        };
16888        let head = self
16889            .selections
16890            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
16891            .head();
16892        let buffer = self.buffer.read(cx);
16893        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16894            return Task::ready(Ok(Navigated::No));
16895        };
16896        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16897            return Task::ready(Ok(Navigated::No));
16898        };
16899
16900        cx.spawn_in(window, async move |editor, cx| {
16901            let Some(definitions) = definitions.await? else {
16902                return Ok(Navigated::No);
16903            };
16904            let navigated = editor
16905                .update_in(cx, |editor, window, cx| {
16906                    editor.navigate_to_hover_links(
16907                        Some(kind),
16908                        definitions
16909                            .into_iter()
16910                            .filter(|location| {
16911                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16912                            })
16913                            .map(HoverLink::Text)
16914                            .collect::<Vec<_>>(),
16915                        split,
16916                        window,
16917                        cx,
16918                    )
16919                })?
16920                .await?;
16921            anyhow::Ok(navigated)
16922        })
16923    }
16924
16925    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16926        let selection = self.selections.newest_anchor();
16927        let head = selection.head();
16928        let tail = selection.tail();
16929
16930        let Some((buffer, start_position)) =
16931            self.buffer.read(cx).text_anchor_for_position(head, cx)
16932        else {
16933            return;
16934        };
16935
16936        let end_position = if head != tail {
16937            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16938                return;
16939            };
16940            Some(pos)
16941        } else {
16942            None
16943        };
16944
16945        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16946            let url = if let Some(end_pos) = end_position {
16947                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16948            } else {
16949                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16950            };
16951
16952            if let Some(url) = url {
16953                cx.update(|window, cx| {
16954                    if parse_zed_link(&url, cx).is_some() {
16955                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16956                    } else {
16957                        cx.open_url(&url);
16958                    }
16959                })?;
16960            }
16961
16962            anyhow::Ok(())
16963        });
16964
16965        url_finder.detach();
16966    }
16967
16968    pub fn open_selected_filename(
16969        &mut self,
16970        _: &OpenSelectedFilename,
16971        window: &mut Window,
16972        cx: &mut Context<Self>,
16973    ) {
16974        let Some(workspace) = self.workspace() else {
16975            return;
16976        };
16977
16978        let position = self.selections.newest_anchor().head();
16979
16980        let Some((buffer, buffer_position)) =
16981            self.buffer.read(cx).text_anchor_for_position(position, cx)
16982        else {
16983            return;
16984        };
16985
16986        let project = self.project.clone();
16987
16988        cx.spawn_in(window, async move |_, cx| {
16989            let result = find_file(&buffer, project, buffer_position, cx).await;
16990
16991            if let Some((_, path)) = result {
16992                workspace
16993                    .update_in(cx, |workspace, window, cx| {
16994                        workspace.open_resolved_path(path, window, cx)
16995                    })?
16996                    .await?;
16997            }
16998            anyhow::Ok(())
16999        })
17000        .detach();
17001    }
17002
17003    pub(crate) fn navigate_to_hover_links(
17004        &mut self,
17005        kind: Option<GotoDefinitionKind>,
17006        definitions: Vec<HoverLink>,
17007        split: bool,
17008        window: &mut Window,
17009        cx: &mut Context<Editor>,
17010    ) -> Task<Result<Navigated>> {
17011        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17012        let mut first_url_or_file = None;
17013        let definitions: Vec<_> = definitions
17014            .into_iter()
17015            .filter_map(|def| match def {
17016                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17017                HoverLink::InlayHint(lsp_location, server_id) => {
17018                    let computation =
17019                        self.compute_target_location(lsp_location, server_id, window, cx);
17020                    Some(cx.background_spawn(computation))
17021                }
17022                HoverLink::Url(url) => {
17023                    first_url_or_file = Some(Either::Left(url));
17024                    None
17025                }
17026                HoverLink::File(path) => {
17027                    first_url_or_file = Some(Either::Right(path));
17028                    None
17029                }
17030            })
17031            .collect();
17032
17033        let Some(workspace) = self.workspace() else {
17034            return Task::ready(Ok(Navigated::No));
17035        };
17036
17037        cx.spawn_in(window, async move |editor, cx| {
17038            let locations: Vec<Location> = future::join_all(definitions)
17039                .await
17040                .into_iter()
17041                .filter_map(|location| location.transpose())
17042                .collect::<Result<_>>()
17043                .context("location tasks")?;
17044            let mut locations = cx.update(|_, cx| {
17045                locations
17046                    .into_iter()
17047                    .map(|location| {
17048                        let buffer = location.buffer.read(cx);
17049                        (location.buffer, location.range.to_point(buffer))
17050                    })
17051                    .into_group_map()
17052            })?;
17053            let mut num_locations = 0;
17054            for ranges in locations.values_mut() {
17055                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17056                ranges.dedup();
17057                num_locations += ranges.len();
17058            }
17059
17060            if num_locations > 1 {
17061                let tab_kind = match kind {
17062                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17063                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17064                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17065                    Some(GotoDefinitionKind::Type) => "Types",
17066                };
17067                let title = editor
17068                    .update_in(cx, |_, _, cx| {
17069                        let target = locations
17070                            .iter()
17071                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17072                            .map(|(buffer, location)| {
17073                                buffer
17074                                    .read(cx)
17075                                    .text_for_range(location.clone())
17076                                    .collect::<String>()
17077                            })
17078                            .filter(|text| !text.contains('\n'))
17079                            .unique()
17080                            .take(3)
17081                            .join(", ");
17082                        if target.is_empty() {
17083                            tab_kind.to_owned()
17084                        } else {
17085                            format!("{tab_kind} for {target}")
17086                        }
17087                    })
17088                    .context("buffer title")?;
17089
17090                let opened = workspace
17091                    .update_in(cx, |workspace, window, cx| {
17092                        let allow_preview = PreviewTabsSettings::get_global(cx)
17093                            .enable_preview_multibuffer_from_code_navigation;
17094                        Self::open_locations_in_multibuffer(
17095                            workspace,
17096                            locations,
17097                            title,
17098                            split,
17099                            allow_preview,
17100                            MultibufferSelectionMode::First,
17101                            window,
17102                            cx,
17103                        )
17104                    })
17105                    .is_ok();
17106
17107                anyhow::Ok(Navigated::from_bool(opened))
17108            } else if num_locations == 0 {
17109                // If there is one url or file, open it directly
17110                match first_url_or_file {
17111                    Some(Either::Left(url)) => {
17112                        cx.update(|_, cx| cx.open_url(&url))?;
17113                        Ok(Navigated::Yes)
17114                    }
17115                    Some(Either::Right(path)) => {
17116                        // TODO(andrew): respect preview tab settings
17117                        //               `enable_keep_preview_on_code_navigation` and
17118                        //               `enable_preview_file_from_code_navigation`
17119                        workspace
17120                            .update_in(cx, |workspace, window, cx| {
17121                                workspace.open_resolved_path(path, window, cx)
17122                            })?
17123                            .await?;
17124                        Ok(Navigated::Yes)
17125                    }
17126                    None => Ok(Navigated::No),
17127                }
17128            } else {
17129                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17130                let target_range = target_ranges.first().unwrap().clone();
17131
17132                editor.update_in(cx, |editor, window, cx| {
17133                    let range = target_range.to_point(target_buffer.read(cx));
17134                    let range = editor.range_for_match(&range);
17135                    let range = collapse_multiline_range(range);
17136
17137                    if !split
17138                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17139                    {
17140                        editor.go_to_singleton_buffer_range(range, window, cx);
17141                    } else {
17142                        let pane = workspace.read(cx).active_pane().clone();
17143                        window.defer(cx, move |window, cx| {
17144                            let target_editor: Entity<Self> =
17145                                workspace.update(cx, |workspace, cx| {
17146                                    let pane = if split {
17147                                        workspace.adjacent_pane(window, cx)
17148                                    } else {
17149                                        workspace.active_pane().clone()
17150                                    };
17151
17152                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17153                                    let keep_old_preview = preview_tabs_settings
17154                                        .enable_keep_preview_on_code_navigation;
17155                                    let allow_new_preview = preview_tabs_settings
17156                                        .enable_preview_file_from_code_navigation;
17157
17158                                    workspace.open_project_item(
17159                                        pane,
17160                                        target_buffer.clone(),
17161                                        true,
17162                                        true,
17163                                        keep_old_preview,
17164                                        allow_new_preview,
17165                                        window,
17166                                        cx,
17167                                    )
17168                                });
17169                            target_editor.update(cx, |target_editor, cx| {
17170                                // When selecting a definition in a different buffer, disable the nav history
17171                                // to avoid creating a history entry at the previous cursor location.
17172                                pane.update(cx, |pane, _| pane.disable_history());
17173                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17174                                pane.update(cx, |pane, _| pane.enable_history());
17175                            });
17176                        });
17177                    }
17178                    Navigated::Yes
17179                })
17180            }
17181        })
17182    }
17183
17184    fn compute_target_location(
17185        &self,
17186        lsp_location: lsp::Location,
17187        server_id: LanguageServerId,
17188        window: &mut Window,
17189        cx: &mut Context<Self>,
17190    ) -> Task<anyhow::Result<Option<Location>>> {
17191        let Some(project) = self.project.clone() else {
17192            return Task::ready(Ok(None));
17193        };
17194
17195        cx.spawn_in(window, async move |editor, cx| {
17196            let location_task = editor.update(cx, |_, cx| {
17197                project.update(cx, |project, cx| {
17198                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17199                })
17200            })?;
17201            let location = Some({
17202                let target_buffer_handle = location_task.await.context("open local buffer")?;
17203                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17204                    let target_start = target_buffer
17205                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17206                    let target_end = target_buffer
17207                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17208                    target_buffer.anchor_after(target_start)
17209                        ..target_buffer.anchor_before(target_end)
17210                })?;
17211                Location {
17212                    buffer: target_buffer_handle,
17213                    range,
17214                }
17215            });
17216            Ok(location)
17217        })
17218    }
17219
17220    fn go_to_next_reference(
17221        &mut self,
17222        _: &GoToNextReference,
17223        window: &mut Window,
17224        cx: &mut Context<Self>,
17225    ) {
17226        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17227        if let Some(task) = task {
17228            task.detach();
17229        };
17230    }
17231
17232    fn go_to_prev_reference(
17233        &mut self,
17234        _: &GoToPreviousReference,
17235        window: &mut Window,
17236        cx: &mut Context<Self>,
17237    ) {
17238        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17239        if let Some(task) = task {
17240            task.detach();
17241        };
17242    }
17243
17244    pub fn go_to_reference_before_or_after_position(
17245        &mut self,
17246        direction: Direction,
17247        count: usize,
17248        window: &mut Window,
17249        cx: &mut Context<Self>,
17250    ) -> Option<Task<Result<()>>> {
17251        let selection = self.selections.newest_anchor();
17252        let head = selection.head();
17253
17254        let multi_buffer = self.buffer.read(cx);
17255
17256        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17257        let workspace = self.workspace()?;
17258        let project = workspace.read(cx).project().clone();
17259        let references =
17260            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17261        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17262            let Some(locations) = references.await? else {
17263                return Ok(());
17264            };
17265
17266            if locations.is_empty() {
17267                // totally normal - the cursor may be on something which is not
17268                // a symbol (e.g. a keyword)
17269                log::info!("no references found under cursor");
17270                return Ok(());
17271            }
17272
17273            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17274
17275            let (locations, current_location_index) =
17276                multi_buffer.update(cx, |multi_buffer, cx| {
17277                    let mut locations = locations
17278                        .into_iter()
17279                        .filter_map(|loc| {
17280                            let start = multi_buffer.buffer_anchor_to_anchor(
17281                                &loc.buffer,
17282                                loc.range.start,
17283                                cx,
17284                            )?;
17285                            let end = multi_buffer.buffer_anchor_to_anchor(
17286                                &loc.buffer,
17287                                loc.range.end,
17288                                cx,
17289                            )?;
17290                            Some(start..end)
17291                        })
17292                        .collect::<Vec<_>>();
17293
17294                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17295                    // There is an O(n) implementation, but given this list will be
17296                    // small (usually <100 items), the extra O(log(n)) factor isn't
17297                    // worth the (surprisingly large amount of) extra complexity.
17298                    locations
17299                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17300
17301                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17302
17303                    let current_location_index = locations.iter().position(|loc| {
17304                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17305                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17306                    });
17307
17308                    (locations, current_location_index)
17309                })?;
17310
17311            let Some(current_location_index) = current_location_index else {
17312                // This indicates something has gone wrong, because we already
17313                // handle the "no references" case above
17314                log::error!(
17315                    "failed to find current reference under cursor. Total references: {}",
17316                    locations.len()
17317                );
17318                return Ok(());
17319            };
17320
17321            let destination_location_index = match direction {
17322                Direction::Next => (current_location_index + count) % locations.len(),
17323                Direction::Prev => {
17324                    (current_location_index + locations.len() - count % locations.len())
17325                        % locations.len()
17326                }
17327            };
17328
17329            // TODO(cameron): is this needed?
17330            // the thinking is to avoid "jumping to the current location" (avoid
17331            // polluting "jumplist" in vim terms)
17332            if current_location_index == destination_location_index {
17333                return Ok(());
17334            }
17335
17336            let Range { start, end } = locations[destination_location_index];
17337
17338            editor.update_in(cx, |editor, window, cx| {
17339                let effects = SelectionEffects::default();
17340
17341                editor.unfold_ranges(&[start..end], false, false, cx);
17342                editor.change_selections(effects, window, cx, |s| {
17343                    s.select_ranges([start..start]);
17344                });
17345            })?;
17346
17347            Ok(())
17348        }))
17349    }
17350
17351    pub fn find_all_references(
17352        &mut self,
17353        _: &FindAllReferences,
17354        window: &mut Window,
17355        cx: &mut Context<Self>,
17356    ) -> Option<Task<Result<Navigated>>> {
17357        let selection = self
17358            .selections
17359            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17360        let multi_buffer = self.buffer.read(cx);
17361        let head = selection.head();
17362
17363        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17364        let head_anchor = multi_buffer_snapshot.anchor_at(
17365            head,
17366            if head < selection.tail() {
17367                Bias::Right
17368            } else {
17369                Bias::Left
17370            },
17371        );
17372
17373        match self
17374            .find_all_references_task_sources
17375            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17376        {
17377            Ok(_) => {
17378                log::info!(
17379                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17380                );
17381                return None;
17382            }
17383            Err(i) => {
17384                self.find_all_references_task_sources.insert(i, head_anchor);
17385            }
17386        }
17387
17388        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17389        let workspace = self.workspace()?;
17390        let project = workspace.read(cx).project().clone();
17391        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17392        Some(cx.spawn_in(window, async move |editor, cx| {
17393            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17394                if let Ok(i) = editor
17395                    .find_all_references_task_sources
17396                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17397                {
17398                    editor.find_all_references_task_sources.remove(i);
17399                }
17400            });
17401
17402            let Some(locations) = references.await? else {
17403                return anyhow::Ok(Navigated::No);
17404            };
17405            let mut locations = cx.update(|_, cx| {
17406                locations
17407                    .into_iter()
17408                    .map(|location| {
17409                        let buffer = location.buffer.read(cx);
17410                        (location.buffer, location.range.to_point(buffer))
17411                    })
17412                    .into_group_map()
17413            })?;
17414            if locations.is_empty() {
17415                return anyhow::Ok(Navigated::No);
17416            }
17417            for ranges in locations.values_mut() {
17418                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17419                ranges.dedup();
17420            }
17421
17422            workspace.update_in(cx, |workspace, window, cx| {
17423                let target = locations
17424                    .iter()
17425                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17426                    .map(|(buffer, location)| {
17427                        buffer
17428                            .read(cx)
17429                            .text_for_range(location.clone())
17430                            .collect::<String>()
17431                    })
17432                    .filter(|text| !text.contains('\n'))
17433                    .unique()
17434                    .take(3)
17435                    .join(", ");
17436                let title = if target.is_empty() {
17437                    "References".to_owned()
17438                } else {
17439                    format!("References to {target}")
17440                };
17441                let allow_preview = PreviewTabsSettings::get_global(cx)
17442                    .enable_preview_multibuffer_from_code_navigation;
17443                Self::open_locations_in_multibuffer(
17444                    workspace,
17445                    locations,
17446                    title,
17447                    false,
17448                    allow_preview,
17449                    MultibufferSelectionMode::First,
17450                    window,
17451                    cx,
17452                );
17453                Navigated::Yes
17454            })
17455        }))
17456    }
17457
17458    /// Opens a multibuffer with the given project locations in it
17459    pub fn open_locations_in_multibuffer(
17460        workspace: &mut Workspace,
17461        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17462        title: String,
17463        split: bool,
17464        allow_preview: bool,
17465        multibuffer_selection_mode: MultibufferSelectionMode,
17466        window: &mut Window,
17467        cx: &mut Context<Workspace>,
17468    ) {
17469        if locations.is_empty() {
17470            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17471            return;
17472        }
17473
17474        let capability = workspace.project().read(cx).capability();
17475        let mut ranges = <Vec<Range<Anchor>>>::new();
17476
17477        // a key to find existing multibuffer editors with the same set of locations
17478        // to prevent us from opening more and more multibuffer tabs for searches and the like
17479        let mut key = (title.clone(), vec![]);
17480        let excerpt_buffer = cx.new(|cx| {
17481            let key = &mut key.1;
17482            let mut multibuffer = MultiBuffer::new(capability);
17483            for (buffer, mut ranges_for_buffer) in locations {
17484                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17485                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17486                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17487                    PathKey::for_buffer(&buffer, cx),
17488                    buffer.clone(),
17489                    ranges_for_buffer,
17490                    multibuffer_context_lines(cx),
17491                    cx,
17492                );
17493                ranges.extend(new_ranges)
17494            }
17495
17496            multibuffer.with_title(title)
17497        });
17498        let existing = workspace.active_pane().update(cx, |pane, cx| {
17499            pane.items()
17500                .filter_map(|item| item.downcast::<Editor>())
17501                .find(|editor| {
17502                    editor
17503                        .read(cx)
17504                        .lookup_key
17505                        .as_ref()
17506                        .and_then(|it| {
17507                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17508                        })
17509                        .is_some_and(|it| *it == key)
17510                })
17511        });
17512        let was_existing = existing.is_some();
17513        let editor = existing.unwrap_or_else(|| {
17514            cx.new(|cx| {
17515                let mut editor = Editor::for_multibuffer(
17516                    excerpt_buffer,
17517                    Some(workspace.project().clone()),
17518                    window,
17519                    cx,
17520                );
17521                editor.lookup_key = Some(Box::new(key));
17522                editor
17523            })
17524        });
17525        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17526            MultibufferSelectionMode::First => {
17527                if let Some(first_range) = ranges.first() {
17528                    editor.change_selections(
17529                        SelectionEffects::no_scroll(),
17530                        window,
17531                        cx,
17532                        |selections| {
17533                            selections.clear_disjoint();
17534                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17535                        },
17536                    );
17537                }
17538                editor.highlight_background::<Self>(
17539                    &ranges,
17540                    |_, theme| theme.colors().editor_highlighted_line_background,
17541                    cx,
17542                );
17543            }
17544            MultibufferSelectionMode::All => {
17545                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17546                    selections.clear_disjoint();
17547                    selections.select_anchor_ranges(ranges);
17548                });
17549            }
17550        });
17551
17552        let item = Box::new(editor);
17553
17554        let pane = if split {
17555            workspace.adjacent_pane(window, cx)
17556        } else {
17557            workspace.active_pane().clone()
17558        };
17559        let activate_pane = split;
17560
17561        let mut destination_index = None;
17562        pane.update(cx, |pane, cx| {
17563            if allow_preview && !was_existing {
17564                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
17565            }
17566            if was_existing && !allow_preview {
17567                pane.unpreview_item_if_preview(item.item_id());
17568            }
17569            pane.add_item(item, activate_pane, true, destination_index, window, cx);
17570        });
17571    }
17572
17573    pub fn rename(
17574        &mut self,
17575        _: &Rename,
17576        window: &mut Window,
17577        cx: &mut Context<Self>,
17578    ) -> Option<Task<Result<()>>> {
17579        use language::ToOffset as _;
17580
17581        let provider = self.semantics_provider.clone()?;
17582        let selection = self.selections.newest_anchor().clone();
17583        let (cursor_buffer, cursor_buffer_position) = self
17584            .buffer
17585            .read(cx)
17586            .text_anchor_for_position(selection.head(), cx)?;
17587        let (tail_buffer, cursor_buffer_position_end) = self
17588            .buffer
17589            .read(cx)
17590            .text_anchor_for_position(selection.tail(), cx)?;
17591        if tail_buffer != cursor_buffer {
17592            return None;
17593        }
17594
17595        let snapshot = cursor_buffer.read(cx).snapshot();
17596        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17597        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17598        let prepare_rename = provider
17599            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17600            .unwrap_or_else(|| Task::ready(Ok(None)));
17601        drop(snapshot);
17602
17603        Some(cx.spawn_in(window, async move |this, cx| {
17604            let rename_range = if let Some(range) = prepare_rename.await? {
17605                Some(range)
17606            } else {
17607                this.update(cx, |this, cx| {
17608                    let buffer = this.buffer.read(cx).snapshot(cx);
17609                    let mut buffer_highlights = this
17610                        .document_highlights_for_position(selection.head(), &buffer)
17611                        .filter(|highlight| {
17612                            highlight.start.excerpt_id == selection.head().excerpt_id
17613                                && highlight.end.excerpt_id == selection.head().excerpt_id
17614                        });
17615                    buffer_highlights
17616                        .next()
17617                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17618                })?
17619            };
17620            if let Some(rename_range) = rename_range {
17621                this.update_in(cx, |this, window, cx| {
17622                    let snapshot = cursor_buffer.read(cx).snapshot();
17623                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17624                    let cursor_offset_in_rename_range =
17625                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17626                    let cursor_offset_in_rename_range_end =
17627                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17628
17629                    this.take_rename(false, window, cx);
17630                    let buffer = this.buffer.read(cx).read(cx);
17631                    let cursor_offset = selection.head().to_offset(&buffer);
17632                    let rename_start =
17633                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17634                    let rename_end = rename_start + rename_buffer_range.len();
17635                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17636                    let mut old_highlight_id = None;
17637                    let old_name: Arc<str> = buffer
17638                        .chunks(rename_start..rename_end, true)
17639                        .map(|chunk| {
17640                            if old_highlight_id.is_none() {
17641                                old_highlight_id = chunk.syntax_highlight_id;
17642                            }
17643                            chunk.text
17644                        })
17645                        .collect::<String>()
17646                        .into();
17647
17648                    drop(buffer);
17649
17650                    // Position the selection in the rename editor so that it matches the current selection.
17651                    this.show_local_selections = false;
17652                    let rename_editor = cx.new(|cx| {
17653                        let mut editor = Editor::single_line(window, cx);
17654                        editor.buffer.update(cx, |buffer, cx| {
17655                            buffer.edit(
17656                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17657                                None,
17658                                cx,
17659                            )
17660                        });
17661                        let cursor_offset_in_rename_range =
17662                            MultiBufferOffset(cursor_offset_in_rename_range);
17663                        let cursor_offset_in_rename_range_end =
17664                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17665                        let rename_selection_range = match cursor_offset_in_rename_range
17666                            .cmp(&cursor_offset_in_rename_range_end)
17667                        {
17668                            Ordering::Equal => {
17669                                editor.select_all(&SelectAll, window, cx);
17670                                return editor;
17671                            }
17672                            Ordering::Less => {
17673                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17674                            }
17675                            Ordering::Greater => {
17676                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17677                            }
17678                        };
17679                        if rename_selection_range.end.0 > old_name.len() {
17680                            editor.select_all(&SelectAll, window, cx);
17681                        } else {
17682                            editor.change_selections(Default::default(), window, cx, |s| {
17683                                s.select_ranges([rename_selection_range]);
17684                            });
17685                        }
17686                        editor
17687                    });
17688                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17689                        if e == &EditorEvent::Focused {
17690                            cx.emit(EditorEvent::FocusedIn)
17691                        }
17692                    })
17693                    .detach();
17694
17695                    let write_highlights =
17696                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17697                    let read_highlights =
17698                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17699                    let ranges = write_highlights
17700                        .iter()
17701                        .flat_map(|(_, ranges)| ranges.iter())
17702                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17703                        .cloned()
17704                        .collect();
17705
17706                    this.highlight_text::<Rename>(
17707                        ranges,
17708                        HighlightStyle {
17709                            fade_out: Some(0.6),
17710                            ..Default::default()
17711                        },
17712                        cx,
17713                    );
17714                    let rename_focus_handle = rename_editor.focus_handle(cx);
17715                    window.focus(&rename_focus_handle);
17716                    let block_id = this.insert_blocks(
17717                        [BlockProperties {
17718                            style: BlockStyle::Flex,
17719                            placement: BlockPlacement::Below(range.start),
17720                            height: Some(1),
17721                            render: Arc::new({
17722                                let rename_editor = rename_editor.clone();
17723                                move |cx: &mut BlockContext| {
17724                                    let mut text_style = cx.editor_style.text.clone();
17725                                    if let Some(highlight_style) = old_highlight_id
17726                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17727                                    {
17728                                        text_style = text_style.highlight(highlight_style);
17729                                    }
17730                                    div()
17731                                        .block_mouse_except_scroll()
17732                                        .pl(cx.anchor_x)
17733                                        .child(EditorElement::new(
17734                                            &rename_editor,
17735                                            EditorStyle {
17736                                                background: cx.theme().system().transparent,
17737                                                local_player: cx.editor_style.local_player,
17738                                                text: text_style,
17739                                                scrollbar_width: cx.editor_style.scrollbar_width,
17740                                                syntax: cx.editor_style.syntax.clone(),
17741                                                status: cx.editor_style.status.clone(),
17742                                                inlay_hints_style: HighlightStyle {
17743                                                    font_weight: Some(FontWeight::BOLD),
17744                                                    ..make_inlay_hints_style(cx.app)
17745                                                },
17746                                                edit_prediction_styles: make_suggestion_styles(
17747                                                    cx.app,
17748                                                ),
17749                                                ..EditorStyle::default()
17750                                            },
17751                                        ))
17752                                        .into_any_element()
17753                                }
17754                            }),
17755                            priority: 0,
17756                        }],
17757                        Some(Autoscroll::fit()),
17758                        cx,
17759                    )[0];
17760                    this.pending_rename = Some(RenameState {
17761                        range,
17762                        old_name,
17763                        editor: rename_editor,
17764                        block_id,
17765                    });
17766                })?;
17767            }
17768
17769            Ok(())
17770        }))
17771    }
17772
17773    pub fn confirm_rename(
17774        &mut self,
17775        _: &ConfirmRename,
17776        window: &mut Window,
17777        cx: &mut Context<Self>,
17778    ) -> Option<Task<Result<()>>> {
17779        let rename = self.take_rename(false, window, cx)?;
17780        let workspace = self.workspace()?.downgrade();
17781        let (buffer, start) = self
17782            .buffer
17783            .read(cx)
17784            .text_anchor_for_position(rename.range.start, cx)?;
17785        let (end_buffer, _) = self
17786            .buffer
17787            .read(cx)
17788            .text_anchor_for_position(rename.range.end, cx)?;
17789        if buffer != end_buffer {
17790            return None;
17791        }
17792
17793        let old_name = rename.old_name;
17794        let new_name = rename.editor.read(cx).text(cx);
17795
17796        let rename = self.semantics_provider.as_ref()?.perform_rename(
17797            &buffer,
17798            start,
17799            new_name.clone(),
17800            cx,
17801        )?;
17802
17803        Some(cx.spawn_in(window, async move |editor, cx| {
17804            let project_transaction = rename.await?;
17805            Self::open_project_transaction(
17806                &editor,
17807                workspace,
17808                project_transaction,
17809                format!("Rename: {}{}", old_name, new_name),
17810                cx,
17811            )
17812            .await?;
17813
17814            editor.update(cx, |editor, cx| {
17815                editor.refresh_document_highlights(cx);
17816            })?;
17817            Ok(())
17818        }))
17819    }
17820
17821    fn take_rename(
17822        &mut self,
17823        moving_cursor: bool,
17824        window: &mut Window,
17825        cx: &mut Context<Self>,
17826    ) -> Option<RenameState> {
17827        let rename = self.pending_rename.take()?;
17828        if rename.editor.focus_handle(cx).is_focused(window) {
17829            window.focus(&self.focus_handle);
17830        }
17831
17832        self.remove_blocks(
17833            [rename.block_id].into_iter().collect(),
17834            Some(Autoscroll::fit()),
17835            cx,
17836        );
17837        self.clear_highlights::<Rename>(cx);
17838        self.show_local_selections = true;
17839
17840        if moving_cursor {
17841            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17842                editor
17843                    .selections
17844                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
17845                    .head()
17846            });
17847
17848            // Update the selection to match the position of the selection inside
17849            // the rename editor.
17850            let snapshot = self.buffer.read(cx).read(cx);
17851            let rename_range = rename.range.to_offset(&snapshot);
17852            let cursor_in_editor = snapshot
17853                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17854                .min(rename_range.end);
17855            drop(snapshot);
17856
17857            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17858                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17859            });
17860        } else {
17861            self.refresh_document_highlights(cx);
17862        }
17863
17864        Some(rename)
17865    }
17866
17867    pub fn pending_rename(&self) -> Option<&RenameState> {
17868        self.pending_rename.as_ref()
17869    }
17870
17871    fn format(
17872        &mut self,
17873        _: &Format,
17874        window: &mut Window,
17875        cx: &mut Context<Self>,
17876    ) -> Option<Task<Result<()>>> {
17877        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17878
17879        let project = match &self.project {
17880            Some(project) => project.clone(),
17881            None => return None,
17882        };
17883
17884        Some(self.perform_format(
17885            project,
17886            FormatTrigger::Manual,
17887            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17888            window,
17889            cx,
17890        ))
17891    }
17892
17893    fn format_selections(
17894        &mut self,
17895        _: &FormatSelections,
17896        window: &mut Window,
17897        cx: &mut Context<Self>,
17898    ) -> Option<Task<Result<()>>> {
17899        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17900
17901        let project = match &self.project {
17902            Some(project) => project.clone(),
17903            None => return None,
17904        };
17905
17906        let ranges = self
17907            .selections
17908            .all_adjusted(&self.display_snapshot(cx))
17909            .into_iter()
17910            .map(|selection| selection.range())
17911            .collect_vec();
17912
17913        Some(self.perform_format(
17914            project,
17915            FormatTrigger::Manual,
17916            FormatTarget::Ranges(ranges),
17917            window,
17918            cx,
17919        ))
17920    }
17921
17922    fn perform_format(
17923        &mut self,
17924        project: Entity<Project>,
17925        trigger: FormatTrigger,
17926        target: FormatTarget,
17927        window: &mut Window,
17928        cx: &mut Context<Self>,
17929    ) -> Task<Result<()>> {
17930        let buffer = self.buffer.clone();
17931        let (buffers, target) = match target {
17932            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17933            FormatTarget::Ranges(selection_ranges) => {
17934                let multi_buffer = buffer.read(cx);
17935                let snapshot = multi_buffer.read(cx);
17936                let mut buffers = HashSet::default();
17937                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17938                    BTreeMap::new();
17939                for selection_range in selection_ranges {
17940                    for (buffer, buffer_range, _) in
17941                        snapshot.range_to_buffer_ranges(selection_range)
17942                    {
17943                        let buffer_id = buffer.remote_id();
17944                        let start = buffer.anchor_before(buffer_range.start);
17945                        let end = buffer.anchor_after(buffer_range.end);
17946                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17947                        buffer_id_to_ranges
17948                            .entry(buffer_id)
17949                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17950                            .or_insert_with(|| vec![start..end]);
17951                    }
17952                }
17953                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17954            }
17955        };
17956
17957        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17958        let selections_prev = transaction_id_prev
17959            .and_then(|transaction_id_prev| {
17960                // default to selections as they were after the last edit, if we have them,
17961                // instead of how they are now.
17962                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17963                // will take you back to where you made the last edit, instead of staying where you scrolled
17964                self.selection_history
17965                    .transaction(transaction_id_prev)
17966                    .map(|t| t.0.clone())
17967            })
17968            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17969
17970        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17971        let format = project.update(cx, |project, cx| {
17972            project.format(buffers, target, true, trigger, cx)
17973        });
17974
17975        cx.spawn_in(window, async move |editor, cx| {
17976            let transaction = futures::select_biased! {
17977                transaction = format.log_err().fuse() => transaction,
17978                () = timeout => {
17979                    log::warn!("timed out waiting for formatting");
17980                    None
17981                }
17982            };
17983
17984            buffer
17985                .update(cx, |buffer, cx| {
17986                    if let Some(transaction) = transaction
17987                        && !buffer.is_singleton()
17988                    {
17989                        buffer.push_transaction(&transaction.0, cx);
17990                    }
17991                    cx.notify();
17992                })
17993                .ok();
17994
17995            if let Some(transaction_id_now) =
17996                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17997            {
17998                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17999                if has_new_transaction {
18000                    _ = editor.update(cx, |editor, _| {
18001                        editor
18002                            .selection_history
18003                            .insert_transaction(transaction_id_now, selections_prev);
18004                    });
18005                }
18006            }
18007
18008            Ok(())
18009        })
18010    }
18011
18012    fn organize_imports(
18013        &mut self,
18014        _: &OrganizeImports,
18015        window: &mut Window,
18016        cx: &mut Context<Self>,
18017    ) -> Option<Task<Result<()>>> {
18018        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18019        let project = match &self.project {
18020            Some(project) => project.clone(),
18021            None => return None,
18022        };
18023        Some(self.perform_code_action_kind(
18024            project,
18025            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18026            window,
18027            cx,
18028        ))
18029    }
18030
18031    fn perform_code_action_kind(
18032        &mut self,
18033        project: Entity<Project>,
18034        kind: CodeActionKind,
18035        window: &mut Window,
18036        cx: &mut Context<Self>,
18037    ) -> Task<Result<()>> {
18038        let buffer = self.buffer.clone();
18039        let buffers = buffer.read(cx).all_buffers();
18040        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18041        let apply_action = project.update(cx, |project, cx| {
18042            project.apply_code_action_kind(buffers, kind, true, cx)
18043        });
18044        cx.spawn_in(window, async move |_, cx| {
18045            let transaction = futures::select_biased! {
18046                () = timeout => {
18047                    log::warn!("timed out waiting for executing code action");
18048                    None
18049                }
18050                transaction = apply_action.log_err().fuse() => transaction,
18051            };
18052            buffer
18053                .update(cx, |buffer, cx| {
18054                    // check if we need this
18055                    if let Some(transaction) = transaction
18056                        && !buffer.is_singleton()
18057                    {
18058                        buffer.push_transaction(&transaction.0, cx);
18059                    }
18060                    cx.notify();
18061                })
18062                .ok();
18063            Ok(())
18064        })
18065    }
18066
18067    pub fn restart_language_server(
18068        &mut self,
18069        _: &RestartLanguageServer,
18070        _: &mut Window,
18071        cx: &mut Context<Self>,
18072    ) {
18073        if let Some(project) = self.project.clone() {
18074            self.buffer.update(cx, |multi_buffer, cx| {
18075                project.update(cx, |project, cx| {
18076                    project.restart_language_servers_for_buffers(
18077                        multi_buffer.all_buffers().into_iter().collect(),
18078                        HashSet::default(),
18079                        cx,
18080                    );
18081                });
18082            })
18083        }
18084    }
18085
18086    pub fn stop_language_server(
18087        &mut self,
18088        _: &StopLanguageServer,
18089        _: &mut Window,
18090        cx: &mut Context<Self>,
18091    ) {
18092        if let Some(project) = self.project.clone() {
18093            self.buffer.update(cx, |multi_buffer, cx| {
18094                project.update(cx, |project, cx| {
18095                    project.stop_language_servers_for_buffers(
18096                        multi_buffer.all_buffers().into_iter().collect(),
18097                        HashSet::default(),
18098                        cx,
18099                    );
18100                });
18101            });
18102            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18103        }
18104    }
18105
18106    fn cancel_language_server_work(
18107        workspace: &mut Workspace,
18108        _: &actions::CancelLanguageServerWork,
18109        _: &mut Window,
18110        cx: &mut Context<Workspace>,
18111    ) {
18112        let project = workspace.project();
18113        let buffers = workspace
18114            .active_item(cx)
18115            .and_then(|item| item.act_as::<Editor>(cx))
18116            .map_or(HashSet::default(), |editor| {
18117                editor.read(cx).buffer.read(cx).all_buffers()
18118            });
18119        project.update(cx, |project, cx| {
18120            project.cancel_language_server_work_for_buffers(buffers, cx);
18121        });
18122    }
18123
18124    fn show_character_palette(
18125        &mut self,
18126        _: &ShowCharacterPalette,
18127        window: &mut Window,
18128        _: &mut Context<Self>,
18129    ) {
18130        window.show_character_palette();
18131    }
18132
18133    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18134        if !self.diagnostics_enabled() {
18135            return;
18136        }
18137
18138        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18139            let buffer = self.buffer.read(cx).snapshot(cx);
18140            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18141            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18142            let is_valid = buffer
18143                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18144                .any(|entry| {
18145                    entry.diagnostic.is_primary
18146                        && !entry.range.is_empty()
18147                        && entry.range.start == primary_range_start
18148                        && entry.diagnostic.message == active_diagnostics.active_message
18149                });
18150
18151            if !is_valid {
18152                self.dismiss_diagnostics(cx);
18153            }
18154        }
18155    }
18156
18157    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18158        match &self.active_diagnostics {
18159            ActiveDiagnostic::Group(group) => Some(group),
18160            _ => None,
18161        }
18162    }
18163
18164    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18165        if !self.diagnostics_enabled() {
18166            return;
18167        }
18168        self.dismiss_diagnostics(cx);
18169        self.active_diagnostics = ActiveDiagnostic::All;
18170    }
18171
18172    fn activate_diagnostics(
18173        &mut self,
18174        buffer_id: BufferId,
18175        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18176        window: &mut Window,
18177        cx: &mut Context<Self>,
18178    ) {
18179        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18180            return;
18181        }
18182        self.dismiss_diagnostics(cx);
18183        let snapshot = self.snapshot(window, cx);
18184        let buffer = self.buffer.read(cx).snapshot(cx);
18185        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18186            return;
18187        };
18188
18189        let diagnostic_group = buffer
18190            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18191            .collect::<Vec<_>>();
18192
18193        let language_registry = self
18194            .project()
18195            .map(|project| project.read(cx).languages().clone());
18196
18197        let blocks = renderer.render_group(
18198            diagnostic_group,
18199            buffer_id,
18200            snapshot,
18201            cx.weak_entity(),
18202            language_registry,
18203            cx,
18204        );
18205
18206        let blocks = self.display_map.update(cx, |display_map, cx| {
18207            display_map.insert_blocks(blocks, cx).into_iter().collect()
18208        });
18209        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18210            active_range: buffer.anchor_before(diagnostic.range.start)
18211                ..buffer.anchor_after(diagnostic.range.end),
18212            active_message: diagnostic.diagnostic.message.clone(),
18213            group_id: diagnostic.diagnostic.group_id,
18214            blocks,
18215        });
18216        cx.notify();
18217    }
18218
18219    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18220        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18221            return;
18222        };
18223
18224        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18225        if let ActiveDiagnostic::Group(group) = prev {
18226            self.display_map.update(cx, |display_map, cx| {
18227                display_map.remove_blocks(group.blocks, cx);
18228            });
18229            cx.notify();
18230        }
18231    }
18232
18233    /// Disable inline diagnostics rendering for this editor.
18234    pub fn disable_inline_diagnostics(&mut self) {
18235        self.inline_diagnostics_enabled = false;
18236        self.inline_diagnostics_update = Task::ready(());
18237        self.inline_diagnostics.clear();
18238    }
18239
18240    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18241        self.diagnostics_enabled = false;
18242        self.dismiss_diagnostics(cx);
18243        self.inline_diagnostics_update = Task::ready(());
18244        self.inline_diagnostics.clear();
18245    }
18246
18247    pub fn disable_word_completions(&mut self) {
18248        self.word_completions_enabled = false;
18249    }
18250
18251    pub fn diagnostics_enabled(&self) -> bool {
18252        self.diagnostics_enabled && self.mode.is_full()
18253    }
18254
18255    pub fn inline_diagnostics_enabled(&self) -> bool {
18256        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18257    }
18258
18259    pub fn show_inline_diagnostics(&self) -> bool {
18260        self.show_inline_diagnostics
18261    }
18262
18263    pub fn toggle_inline_diagnostics(
18264        &mut self,
18265        _: &ToggleInlineDiagnostics,
18266        window: &mut Window,
18267        cx: &mut Context<Editor>,
18268    ) {
18269        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18270        self.refresh_inline_diagnostics(false, window, cx);
18271    }
18272
18273    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18274        self.diagnostics_max_severity = severity;
18275        self.display_map.update(cx, |display_map, _| {
18276            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18277        });
18278    }
18279
18280    pub fn toggle_diagnostics(
18281        &mut self,
18282        _: &ToggleDiagnostics,
18283        window: &mut Window,
18284        cx: &mut Context<Editor>,
18285    ) {
18286        if !self.diagnostics_enabled() {
18287            return;
18288        }
18289
18290        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18291            EditorSettings::get_global(cx)
18292                .diagnostics_max_severity
18293                .filter(|severity| severity != &DiagnosticSeverity::Off)
18294                .unwrap_or(DiagnosticSeverity::Hint)
18295        } else {
18296            DiagnosticSeverity::Off
18297        };
18298        self.set_max_diagnostics_severity(new_severity, cx);
18299        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18300            self.active_diagnostics = ActiveDiagnostic::None;
18301            self.inline_diagnostics_update = Task::ready(());
18302            self.inline_diagnostics.clear();
18303        } else {
18304            self.refresh_inline_diagnostics(false, window, cx);
18305        }
18306
18307        cx.notify();
18308    }
18309
18310    pub fn toggle_minimap(
18311        &mut self,
18312        _: &ToggleMinimap,
18313        window: &mut Window,
18314        cx: &mut Context<Editor>,
18315    ) {
18316        if self.supports_minimap(cx) {
18317            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18318        }
18319    }
18320
18321    fn refresh_inline_diagnostics(
18322        &mut self,
18323        debounce: bool,
18324        window: &mut Window,
18325        cx: &mut Context<Self>,
18326    ) {
18327        let max_severity = ProjectSettings::get_global(cx)
18328            .diagnostics
18329            .inline
18330            .max_severity
18331            .unwrap_or(self.diagnostics_max_severity);
18332
18333        if !self.inline_diagnostics_enabled()
18334            || !self.diagnostics_enabled()
18335            || !self.show_inline_diagnostics
18336            || max_severity == DiagnosticSeverity::Off
18337        {
18338            self.inline_diagnostics_update = Task::ready(());
18339            self.inline_diagnostics.clear();
18340            return;
18341        }
18342
18343        let debounce_ms = ProjectSettings::get_global(cx)
18344            .diagnostics
18345            .inline
18346            .update_debounce_ms;
18347        let debounce = if debounce && debounce_ms > 0 {
18348            Some(Duration::from_millis(debounce_ms))
18349        } else {
18350            None
18351        };
18352        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18353            if let Some(debounce) = debounce {
18354                cx.background_executor().timer(debounce).await;
18355            }
18356            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18357                editor
18358                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18359                    .ok()
18360            }) else {
18361                return;
18362            };
18363
18364            let new_inline_diagnostics = cx
18365                .background_spawn(async move {
18366                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18367                    for diagnostic_entry in
18368                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18369                    {
18370                        let message = diagnostic_entry
18371                            .diagnostic
18372                            .message
18373                            .split_once('\n')
18374                            .map(|(line, _)| line)
18375                            .map(SharedString::new)
18376                            .unwrap_or_else(|| {
18377                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18378                            });
18379                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18380                        let (Ok(i) | Err(i)) = inline_diagnostics
18381                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18382                        inline_diagnostics.insert(
18383                            i,
18384                            (
18385                                start_anchor,
18386                                InlineDiagnostic {
18387                                    message,
18388                                    group_id: diagnostic_entry.diagnostic.group_id,
18389                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18390                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18391                                    severity: diagnostic_entry.diagnostic.severity,
18392                                },
18393                            ),
18394                        );
18395                    }
18396                    inline_diagnostics
18397                })
18398                .await;
18399
18400            editor
18401                .update(cx, |editor, cx| {
18402                    editor.inline_diagnostics = new_inline_diagnostics;
18403                    cx.notify();
18404                })
18405                .ok();
18406        });
18407    }
18408
18409    fn pull_diagnostics(
18410        &mut self,
18411        buffer_id: Option<BufferId>,
18412        window: &Window,
18413        cx: &mut Context<Self>,
18414    ) -> Option<()> {
18415        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18416            return None;
18417        }
18418        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18419            .diagnostics
18420            .lsp_pull_diagnostics;
18421        if !pull_diagnostics_settings.enabled {
18422            return None;
18423        }
18424        let project = self.project()?.downgrade();
18425
18426        let mut edited_buffer_ids = HashSet::default();
18427        let mut edited_worktree_ids = HashSet::default();
18428        let edited_buffers = match buffer_id {
18429            Some(buffer_id) => {
18430                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18431                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18432                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18433                edited_worktree_ids.insert(worktree_id);
18434                vec![buffer]
18435            }
18436            None => self
18437                .buffer()
18438                .read(cx)
18439                .all_buffers()
18440                .into_iter()
18441                .filter(|buffer| {
18442                    let buffer = buffer.read(cx);
18443                    match buffer.file().map(|f| f.worktree_id(cx)) {
18444                        Some(worktree_id) => {
18445                            edited_buffer_ids.insert(buffer.remote_id());
18446                            edited_worktree_ids.insert(worktree_id);
18447                            true
18448                        }
18449                        None => false,
18450                    }
18451                })
18452                .collect::<Vec<_>>(),
18453        };
18454
18455        if edited_buffers.is_empty() {
18456            self.pull_diagnostics_task = Task::ready(());
18457            self.pull_diagnostics_background_task = Task::ready(());
18458            return None;
18459        }
18460
18461        let mut already_used_buffers = HashSet::default();
18462        let related_open_buffers = self
18463            .workspace
18464            .as_ref()
18465            .and_then(|(workspace, _)| workspace.upgrade())
18466            .into_iter()
18467            .flat_map(|workspace| workspace.read(cx).panes())
18468            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18469            .filter(|editor| editor != &cx.entity())
18470            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18471            .filter(|buffer| {
18472                let buffer = buffer.read(cx);
18473                let buffer_id = buffer.remote_id();
18474                if already_used_buffers.insert(buffer_id) {
18475                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18476                        return !edited_buffer_ids.contains(&buffer_id)
18477                            && !edited_worktree_ids.contains(&worktree_id);
18478                    }
18479                }
18480                false
18481            })
18482            .collect::<Vec<_>>();
18483
18484        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18485        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18486            if buffers.is_empty() {
18487                return Task::ready(());
18488            }
18489            let project_weak = project.clone();
18490            cx.spawn_in(window, async move |_, cx| {
18491                cx.background_executor().timer(delay).await;
18492
18493                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18494                    buffers
18495                        .into_iter()
18496                        .filter_map(|buffer| {
18497                            project_weak
18498                                .update(cx, |project, cx| {
18499                                    project.lsp_store().update(cx, |lsp_store, cx| {
18500                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18501                                    })
18502                                })
18503                                .ok()
18504                        })
18505                        .collect::<FuturesUnordered<_>>()
18506                }) else {
18507                    return;
18508                };
18509
18510                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18511                    if let Err(e) = pull_task {
18512                        log::error!("Failed to update project diagnostics: {e:#}");
18513                    }
18514                }
18515            })
18516        };
18517
18518        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18519        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18520
18521        Some(())
18522    }
18523
18524    pub fn set_selections_from_remote(
18525        &mut self,
18526        selections: Vec<Selection<Anchor>>,
18527        pending_selection: Option<Selection<Anchor>>,
18528        window: &mut Window,
18529        cx: &mut Context<Self>,
18530    ) {
18531        let old_cursor_position = self.selections.newest_anchor().head();
18532        self.selections
18533            .change_with(&self.display_snapshot(cx), |s| {
18534                s.select_anchors(selections);
18535                if let Some(pending_selection) = pending_selection {
18536                    s.set_pending(pending_selection, SelectMode::Character);
18537                } else {
18538                    s.clear_pending();
18539                }
18540            });
18541        self.selections_did_change(
18542            false,
18543            &old_cursor_position,
18544            SelectionEffects::default(),
18545            window,
18546            cx,
18547        );
18548    }
18549
18550    pub fn transact(
18551        &mut self,
18552        window: &mut Window,
18553        cx: &mut Context<Self>,
18554        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18555    ) -> Option<TransactionId> {
18556        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18557            this.start_transaction_at(Instant::now(), window, cx);
18558            update(this, window, cx);
18559            this.end_transaction_at(Instant::now(), cx)
18560        })
18561    }
18562
18563    pub fn start_transaction_at(
18564        &mut self,
18565        now: Instant,
18566        window: &mut Window,
18567        cx: &mut Context<Self>,
18568    ) -> Option<TransactionId> {
18569        self.end_selection(window, cx);
18570        if let Some(tx_id) = self
18571            .buffer
18572            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18573        {
18574            self.selection_history
18575                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18576            cx.emit(EditorEvent::TransactionBegun {
18577                transaction_id: tx_id,
18578            });
18579            Some(tx_id)
18580        } else {
18581            None
18582        }
18583    }
18584
18585    pub fn end_transaction_at(
18586        &mut self,
18587        now: Instant,
18588        cx: &mut Context<Self>,
18589    ) -> Option<TransactionId> {
18590        if let Some(transaction_id) = self
18591            .buffer
18592            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18593        {
18594            if let Some((_, end_selections)) =
18595                self.selection_history.transaction_mut(transaction_id)
18596            {
18597                *end_selections = Some(self.selections.disjoint_anchors_arc());
18598            } else {
18599                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18600            }
18601
18602            cx.emit(EditorEvent::Edited { transaction_id });
18603            Some(transaction_id)
18604        } else {
18605            None
18606        }
18607    }
18608
18609    pub fn modify_transaction_selection_history(
18610        &mut self,
18611        transaction_id: TransactionId,
18612        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18613    ) -> bool {
18614        self.selection_history
18615            .transaction_mut(transaction_id)
18616            .map(modify)
18617            .is_some()
18618    }
18619
18620    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18621        if self.selection_mark_mode {
18622            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18623                s.move_with(|_, sel| {
18624                    sel.collapse_to(sel.head(), SelectionGoal::None);
18625                });
18626            })
18627        }
18628        self.selection_mark_mode = true;
18629        cx.notify();
18630    }
18631
18632    pub fn swap_selection_ends(
18633        &mut self,
18634        _: &actions::SwapSelectionEnds,
18635        window: &mut Window,
18636        cx: &mut Context<Self>,
18637    ) {
18638        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18639            s.move_with(|_, sel| {
18640                if sel.start != sel.end {
18641                    sel.reversed = !sel.reversed
18642                }
18643            });
18644        });
18645        self.request_autoscroll(Autoscroll::newest(), cx);
18646        cx.notify();
18647    }
18648
18649    pub fn toggle_focus(
18650        workspace: &mut Workspace,
18651        _: &actions::ToggleFocus,
18652        window: &mut Window,
18653        cx: &mut Context<Workspace>,
18654    ) {
18655        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18656            return;
18657        };
18658        workspace.activate_item(&item, true, true, window, cx);
18659    }
18660
18661    pub fn toggle_fold(
18662        &mut self,
18663        _: &actions::ToggleFold,
18664        window: &mut Window,
18665        cx: &mut Context<Self>,
18666    ) {
18667        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18668            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18669            let selection = self.selections.newest::<Point>(&display_map);
18670
18671            let range = if selection.is_empty() {
18672                let point = selection.head().to_display_point(&display_map);
18673                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18674                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18675                    .to_point(&display_map);
18676                start..end
18677            } else {
18678                selection.range()
18679            };
18680            if display_map.folds_in_range(range).next().is_some() {
18681                self.unfold_lines(&Default::default(), window, cx)
18682            } else {
18683                self.fold(&Default::default(), window, cx)
18684            }
18685        } else {
18686            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18687            let buffer_ids: HashSet<_> = self
18688                .selections
18689                .disjoint_anchor_ranges()
18690                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18691                .collect();
18692
18693            let should_unfold = buffer_ids
18694                .iter()
18695                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18696
18697            for buffer_id in buffer_ids {
18698                if should_unfold {
18699                    self.unfold_buffer(buffer_id, cx);
18700                } else {
18701                    self.fold_buffer(buffer_id, cx);
18702                }
18703            }
18704        }
18705    }
18706
18707    pub fn toggle_fold_recursive(
18708        &mut self,
18709        _: &actions::ToggleFoldRecursive,
18710        window: &mut Window,
18711        cx: &mut Context<Self>,
18712    ) {
18713        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18714
18715        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18716        let range = if selection.is_empty() {
18717            let point = selection.head().to_display_point(&display_map);
18718            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18719            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18720                .to_point(&display_map);
18721            start..end
18722        } else {
18723            selection.range()
18724        };
18725        if display_map.folds_in_range(range).next().is_some() {
18726            self.unfold_recursive(&Default::default(), window, cx)
18727        } else {
18728            self.fold_recursive(&Default::default(), window, cx)
18729        }
18730    }
18731
18732    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18733        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18734            let mut to_fold = Vec::new();
18735            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18736            let selections = self.selections.all_adjusted(&display_map);
18737
18738            for selection in selections {
18739                let range = selection.range().sorted();
18740                let buffer_start_row = range.start.row;
18741
18742                if range.start.row != range.end.row {
18743                    let mut found = false;
18744                    let mut row = range.start.row;
18745                    while row <= range.end.row {
18746                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18747                        {
18748                            found = true;
18749                            row = crease.range().end.row + 1;
18750                            to_fold.push(crease);
18751                        } else {
18752                            row += 1
18753                        }
18754                    }
18755                    if found {
18756                        continue;
18757                    }
18758                }
18759
18760                for row in (0..=range.start.row).rev() {
18761                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18762                        && crease.range().end.row >= buffer_start_row
18763                    {
18764                        to_fold.push(crease);
18765                        if row <= range.start.row {
18766                            break;
18767                        }
18768                    }
18769                }
18770            }
18771
18772            self.fold_creases(to_fold, true, window, cx);
18773        } else {
18774            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18775            let buffer_ids = self
18776                .selections
18777                .disjoint_anchor_ranges()
18778                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18779                .collect::<HashSet<_>>();
18780            for buffer_id in buffer_ids {
18781                self.fold_buffer(buffer_id, cx);
18782            }
18783        }
18784    }
18785
18786    pub fn toggle_fold_all(
18787        &mut self,
18788        _: &actions::ToggleFoldAll,
18789        window: &mut Window,
18790        cx: &mut Context<Self>,
18791    ) {
18792        if self.buffer.read(cx).is_singleton() {
18793            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18794            let has_folds = display_map
18795                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
18796                .next()
18797                .is_some();
18798
18799            if has_folds {
18800                self.unfold_all(&actions::UnfoldAll, window, cx);
18801            } else {
18802                self.fold_all(&actions::FoldAll, window, cx);
18803            }
18804        } else {
18805            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18806            let should_unfold = buffer_ids
18807                .iter()
18808                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18809
18810            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18811                editor
18812                    .update_in(cx, |editor, _, cx| {
18813                        for buffer_id in buffer_ids {
18814                            if should_unfold {
18815                                editor.unfold_buffer(buffer_id, cx);
18816                            } else {
18817                                editor.fold_buffer(buffer_id, cx);
18818                            }
18819                        }
18820                    })
18821                    .ok();
18822            });
18823        }
18824    }
18825
18826    fn fold_at_level(
18827        &mut self,
18828        fold_at: &FoldAtLevel,
18829        window: &mut Window,
18830        cx: &mut Context<Self>,
18831    ) {
18832        if !self.buffer.read(cx).is_singleton() {
18833            return;
18834        }
18835
18836        let fold_at_level = fold_at.0;
18837        let snapshot = self.buffer.read(cx).snapshot(cx);
18838        let mut to_fold = Vec::new();
18839        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18840
18841        let row_ranges_to_keep: Vec<Range<u32>> = self
18842            .selections
18843            .all::<Point>(&self.display_snapshot(cx))
18844            .into_iter()
18845            .map(|sel| sel.start.row..sel.end.row)
18846            .collect();
18847
18848        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18849            while start_row < end_row {
18850                match self
18851                    .snapshot(window, cx)
18852                    .crease_for_buffer_row(MultiBufferRow(start_row))
18853                {
18854                    Some(crease) => {
18855                        let nested_start_row = crease.range().start.row + 1;
18856                        let nested_end_row = crease.range().end.row;
18857
18858                        if current_level < fold_at_level {
18859                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18860                        } else if current_level == fold_at_level {
18861                            // Fold iff there is no selection completely contained within the fold region
18862                            if !row_ranges_to_keep.iter().any(|selection| {
18863                                selection.end >= nested_start_row
18864                                    && selection.start <= nested_end_row
18865                            }) {
18866                                to_fold.push(crease);
18867                            }
18868                        }
18869
18870                        start_row = nested_end_row + 1;
18871                    }
18872                    None => start_row += 1,
18873                }
18874            }
18875        }
18876
18877        self.fold_creases(to_fold, true, window, cx);
18878    }
18879
18880    pub fn fold_at_level_1(
18881        &mut self,
18882        _: &actions::FoldAtLevel1,
18883        window: &mut Window,
18884        cx: &mut Context<Self>,
18885    ) {
18886        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18887    }
18888
18889    pub fn fold_at_level_2(
18890        &mut self,
18891        _: &actions::FoldAtLevel2,
18892        window: &mut Window,
18893        cx: &mut Context<Self>,
18894    ) {
18895        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18896    }
18897
18898    pub fn fold_at_level_3(
18899        &mut self,
18900        _: &actions::FoldAtLevel3,
18901        window: &mut Window,
18902        cx: &mut Context<Self>,
18903    ) {
18904        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18905    }
18906
18907    pub fn fold_at_level_4(
18908        &mut self,
18909        _: &actions::FoldAtLevel4,
18910        window: &mut Window,
18911        cx: &mut Context<Self>,
18912    ) {
18913        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18914    }
18915
18916    pub fn fold_at_level_5(
18917        &mut self,
18918        _: &actions::FoldAtLevel5,
18919        window: &mut Window,
18920        cx: &mut Context<Self>,
18921    ) {
18922        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18923    }
18924
18925    pub fn fold_at_level_6(
18926        &mut self,
18927        _: &actions::FoldAtLevel6,
18928        window: &mut Window,
18929        cx: &mut Context<Self>,
18930    ) {
18931        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18932    }
18933
18934    pub fn fold_at_level_7(
18935        &mut self,
18936        _: &actions::FoldAtLevel7,
18937        window: &mut Window,
18938        cx: &mut Context<Self>,
18939    ) {
18940        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18941    }
18942
18943    pub fn fold_at_level_8(
18944        &mut self,
18945        _: &actions::FoldAtLevel8,
18946        window: &mut Window,
18947        cx: &mut Context<Self>,
18948    ) {
18949        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18950    }
18951
18952    pub fn fold_at_level_9(
18953        &mut self,
18954        _: &actions::FoldAtLevel9,
18955        window: &mut Window,
18956        cx: &mut Context<Self>,
18957    ) {
18958        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18959    }
18960
18961    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18962        if self.buffer.read(cx).is_singleton() {
18963            let mut fold_ranges = Vec::new();
18964            let snapshot = self.buffer.read(cx).snapshot(cx);
18965
18966            for row in 0..snapshot.max_row().0 {
18967                if let Some(foldable_range) = self
18968                    .snapshot(window, cx)
18969                    .crease_for_buffer_row(MultiBufferRow(row))
18970                {
18971                    fold_ranges.push(foldable_range);
18972                }
18973            }
18974
18975            self.fold_creases(fold_ranges, true, window, cx);
18976        } else {
18977            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18978                editor
18979                    .update_in(cx, |editor, _, cx| {
18980                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18981                            editor.fold_buffer(buffer_id, cx);
18982                        }
18983                    })
18984                    .ok();
18985            });
18986        }
18987    }
18988
18989    pub fn fold_function_bodies(
18990        &mut self,
18991        _: &actions::FoldFunctionBodies,
18992        window: &mut Window,
18993        cx: &mut Context<Self>,
18994    ) {
18995        let snapshot = self.buffer.read(cx).snapshot(cx);
18996
18997        let ranges = snapshot
18998            .text_object_ranges(
18999                MultiBufferOffset(0)..snapshot.len(),
19000                TreeSitterOptions::default(),
19001            )
19002            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19003            .collect::<Vec<_>>();
19004
19005        let creases = ranges
19006            .into_iter()
19007            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19008            .collect();
19009
19010        self.fold_creases(creases, true, window, cx);
19011    }
19012
19013    pub fn fold_recursive(
19014        &mut self,
19015        _: &actions::FoldRecursive,
19016        window: &mut Window,
19017        cx: &mut Context<Self>,
19018    ) {
19019        let mut to_fold = Vec::new();
19020        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19021        let selections = self.selections.all_adjusted(&display_map);
19022
19023        for selection in selections {
19024            let range = selection.range().sorted();
19025            let buffer_start_row = range.start.row;
19026
19027            if range.start.row != range.end.row {
19028                let mut found = false;
19029                for row in range.start.row..=range.end.row {
19030                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19031                        found = true;
19032                        to_fold.push(crease);
19033                    }
19034                }
19035                if found {
19036                    continue;
19037                }
19038            }
19039
19040            for row in (0..=range.start.row).rev() {
19041                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19042                    if crease.range().end.row >= buffer_start_row {
19043                        to_fold.push(crease);
19044                    } else {
19045                        break;
19046                    }
19047                }
19048            }
19049        }
19050
19051        self.fold_creases(to_fold, true, window, cx);
19052    }
19053
19054    pub fn fold_at(
19055        &mut self,
19056        buffer_row: MultiBufferRow,
19057        window: &mut Window,
19058        cx: &mut Context<Self>,
19059    ) {
19060        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19061
19062        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19063            let autoscroll = self
19064                .selections
19065                .all::<Point>(&display_map)
19066                .iter()
19067                .any(|selection| crease.range().overlaps(&selection.range()));
19068
19069            self.fold_creases(vec![crease], autoscroll, window, cx);
19070        }
19071    }
19072
19073    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19074        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19075            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19076            let buffer = display_map.buffer_snapshot();
19077            let selections = self.selections.all::<Point>(&display_map);
19078            let ranges = selections
19079                .iter()
19080                .map(|s| {
19081                    let range = s.display_range(&display_map).sorted();
19082                    let mut start = range.start.to_point(&display_map);
19083                    let mut end = range.end.to_point(&display_map);
19084                    start.column = 0;
19085                    end.column = buffer.line_len(MultiBufferRow(end.row));
19086                    start..end
19087                })
19088                .collect::<Vec<_>>();
19089
19090            self.unfold_ranges(&ranges, true, true, cx);
19091        } else {
19092            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19093            let buffer_ids = self
19094                .selections
19095                .disjoint_anchor_ranges()
19096                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19097                .collect::<HashSet<_>>();
19098            for buffer_id in buffer_ids {
19099                self.unfold_buffer(buffer_id, cx);
19100            }
19101        }
19102    }
19103
19104    pub fn unfold_recursive(
19105        &mut self,
19106        _: &UnfoldRecursive,
19107        _window: &mut Window,
19108        cx: &mut Context<Self>,
19109    ) {
19110        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19111        let selections = self.selections.all::<Point>(&display_map);
19112        let ranges = selections
19113            .iter()
19114            .map(|s| {
19115                let mut range = s.display_range(&display_map).sorted();
19116                *range.start.column_mut() = 0;
19117                *range.end.column_mut() = display_map.line_len(range.end.row());
19118                let start = range.start.to_point(&display_map);
19119                let end = range.end.to_point(&display_map);
19120                start..end
19121            })
19122            .collect::<Vec<_>>();
19123
19124        self.unfold_ranges(&ranges, true, true, cx);
19125    }
19126
19127    pub fn unfold_at(
19128        &mut self,
19129        buffer_row: MultiBufferRow,
19130        _window: &mut Window,
19131        cx: &mut Context<Self>,
19132    ) {
19133        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19134
19135        let intersection_range = Point::new(buffer_row.0, 0)
19136            ..Point::new(
19137                buffer_row.0,
19138                display_map.buffer_snapshot().line_len(buffer_row),
19139            );
19140
19141        let autoscroll = self
19142            .selections
19143            .all::<Point>(&display_map)
19144            .iter()
19145            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19146
19147        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19148    }
19149
19150    pub fn unfold_all(
19151        &mut self,
19152        _: &actions::UnfoldAll,
19153        _window: &mut Window,
19154        cx: &mut Context<Self>,
19155    ) {
19156        if self.buffer.read(cx).is_singleton() {
19157            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19158            self.unfold_ranges(
19159                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19160                true,
19161                true,
19162                cx,
19163            );
19164        } else {
19165            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19166                editor
19167                    .update(cx, |editor, cx| {
19168                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19169                            editor.unfold_buffer(buffer_id, cx);
19170                        }
19171                    })
19172                    .ok();
19173            });
19174        }
19175    }
19176
19177    pub fn fold_selected_ranges(
19178        &mut self,
19179        _: &FoldSelectedRanges,
19180        window: &mut Window,
19181        cx: &mut Context<Self>,
19182    ) {
19183        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19184        let selections = self.selections.all_adjusted(&display_map);
19185        let ranges = selections
19186            .into_iter()
19187            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19188            .collect::<Vec<_>>();
19189        self.fold_creases(ranges, true, window, cx);
19190    }
19191
19192    pub fn fold_ranges<T: ToOffset + Clone>(
19193        &mut self,
19194        ranges: Vec<Range<T>>,
19195        auto_scroll: bool,
19196        window: &mut Window,
19197        cx: &mut Context<Self>,
19198    ) {
19199        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19200        let ranges = ranges
19201            .into_iter()
19202            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19203            .collect::<Vec<_>>();
19204        self.fold_creases(ranges, auto_scroll, window, cx);
19205    }
19206
19207    pub fn fold_creases<T: ToOffset + Clone>(
19208        &mut self,
19209        creases: Vec<Crease<T>>,
19210        auto_scroll: bool,
19211        _window: &mut Window,
19212        cx: &mut Context<Self>,
19213    ) {
19214        if creases.is_empty() {
19215            return;
19216        }
19217
19218        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19219
19220        if auto_scroll {
19221            self.request_autoscroll(Autoscroll::fit(), cx);
19222        }
19223
19224        cx.notify();
19225
19226        self.scrollbar_marker_state.dirty = true;
19227        self.folds_did_change(cx);
19228    }
19229
19230    /// Removes any folds whose ranges intersect any of the given ranges.
19231    pub fn unfold_ranges<T: ToOffset + Clone>(
19232        &mut self,
19233        ranges: &[Range<T>],
19234        inclusive: bool,
19235        auto_scroll: bool,
19236        cx: &mut Context<Self>,
19237    ) {
19238        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19239            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19240        });
19241        self.folds_did_change(cx);
19242    }
19243
19244    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19245        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19246            return;
19247        }
19248
19249        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19250        self.display_map.update(cx, |display_map, cx| {
19251            display_map.fold_buffers([buffer_id], cx)
19252        });
19253
19254        let snapshot = self.display_snapshot(cx);
19255        self.selections.change_with(&snapshot, |selections| {
19256            selections.remove_selections_from_buffer(buffer_id);
19257        });
19258
19259        cx.emit(EditorEvent::BufferFoldToggled {
19260            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19261            folded: true,
19262        });
19263        cx.notify();
19264    }
19265
19266    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19267        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19268            return;
19269        }
19270        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19271        self.display_map.update(cx, |display_map, cx| {
19272            display_map.unfold_buffers([buffer_id], cx);
19273        });
19274        cx.emit(EditorEvent::BufferFoldToggled {
19275            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19276            folded: false,
19277        });
19278        cx.notify();
19279    }
19280
19281    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19282        self.display_map.read(cx).is_buffer_folded(buffer)
19283    }
19284
19285    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19286        self.display_map.read(cx).folded_buffers()
19287    }
19288
19289    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19290        self.display_map.update(cx, |display_map, cx| {
19291            display_map.disable_header_for_buffer(buffer_id, cx);
19292        });
19293        cx.notify();
19294    }
19295
19296    /// Removes any folds with the given ranges.
19297    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19298        &mut self,
19299        ranges: &[Range<T>],
19300        type_id: TypeId,
19301        auto_scroll: bool,
19302        cx: &mut Context<Self>,
19303    ) {
19304        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19305            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19306        });
19307        self.folds_did_change(cx);
19308    }
19309
19310    fn remove_folds_with<T: ToOffset + Clone>(
19311        &mut self,
19312        ranges: &[Range<T>],
19313        auto_scroll: bool,
19314        cx: &mut Context<Self>,
19315        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19316    ) {
19317        if ranges.is_empty() {
19318            return;
19319        }
19320
19321        let mut buffers_affected = HashSet::default();
19322        let multi_buffer = self.buffer().read(cx);
19323        for range in ranges {
19324            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19325                buffers_affected.insert(buffer.read(cx).remote_id());
19326            };
19327        }
19328
19329        self.display_map.update(cx, update);
19330
19331        if auto_scroll {
19332            self.request_autoscroll(Autoscroll::fit(), cx);
19333        }
19334
19335        cx.notify();
19336        self.scrollbar_marker_state.dirty = true;
19337        self.active_indent_guides_state.dirty = true;
19338    }
19339
19340    pub fn update_renderer_widths(
19341        &mut self,
19342        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19343        cx: &mut Context<Self>,
19344    ) -> bool {
19345        self.display_map
19346            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19347    }
19348
19349    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19350        self.display_map.read(cx).fold_placeholder.clone()
19351    }
19352
19353    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19354        self.use_base_text_line_numbers = show;
19355    }
19356
19357    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19358        self.buffer.update(cx, |buffer, cx| {
19359            buffer.set_all_diff_hunks_expanded(cx);
19360        });
19361    }
19362
19363    pub fn expand_all_diff_hunks(
19364        &mut self,
19365        _: &ExpandAllDiffHunks,
19366        _window: &mut Window,
19367        cx: &mut Context<Self>,
19368    ) {
19369        self.buffer.update(cx, |buffer, cx| {
19370            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19371        });
19372    }
19373
19374    pub fn collapse_all_diff_hunks(
19375        &mut self,
19376        _: &CollapseAllDiffHunks,
19377        _window: &mut Window,
19378        cx: &mut Context<Self>,
19379    ) {
19380        self.buffer.update(cx, |buffer, cx| {
19381            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19382        });
19383    }
19384
19385    pub fn toggle_selected_diff_hunks(
19386        &mut self,
19387        _: &ToggleSelectedDiffHunks,
19388        _window: &mut Window,
19389        cx: &mut Context<Self>,
19390    ) {
19391        let ranges: Vec<_> = self
19392            .selections
19393            .disjoint_anchors()
19394            .iter()
19395            .map(|s| s.range())
19396            .collect();
19397        self.toggle_diff_hunks_in_ranges(ranges, cx);
19398    }
19399
19400    pub fn diff_hunks_in_ranges<'a>(
19401        &'a self,
19402        ranges: &'a [Range<Anchor>],
19403        buffer: &'a MultiBufferSnapshot,
19404    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19405        ranges.iter().flat_map(move |range| {
19406            let end_excerpt_id = range.end.excerpt_id;
19407            let range = range.to_point(buffer);
19408            let mut peek_end = range.end;
19409            if range.end.row < buffer.max_row().0 {
19410                peek_end = Point::new(range.end.row + 1, 0);
19411            }
19412            buffer
19413                .diff_hunks_in_range(range.start..peek_end)
19414                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19415        })
19416    }
19417
19418    pub fn has_stageable_diff_hunks_in_ranges(
19419        &self,
19420        ranges: &[Range<Anchor>],
19421        snapshot: &MultiBufferSnapshot,
19422    ) -> bool {
19423        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19424        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19425    }
19426
19427    pub fn toggle_staged_selected_diff_hunks(
19428        &mut self,
19429        _: &::git::ToggleStaged,
19430        _: &mut Window,
19431        cx: &mut Context<Self>,
19432    ) {
19433        let snapshot = self.buffer.read(cx).snapshot(cx);
19434        let ranges: Vec<_> = self
19435            .selections
19436            .disjoint_anchors()
19437            .iter()
19438            .map(|s| s.range())
19439            .collect();
19440        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19441        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19442    }
19443
19444    pub fn set_render_diff_hunk_controls(
19445        &mut self,
19446        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19447        cx: &mut Context<Self>,
19448    ) {
19449        self.render_diff_hunk_controls = render_diff_hunk_controls;
19450        cx.notify();
19451    }
19452
19453    pub fn stage_and_next(
19454        &mut self,
19455        _: &::git::StageAndNext,
19456        window: &mut Window,
19457        cx: &mut Context<Self>,
19458    ) {
19459        self.do_stage_or_unstage_and_next(true, window, cx);
19460    }
19461
19462    pub fn unstage_and_next(
19463        &mut self,
19464        _: &::git::UnstageAndNext,
19465        window: &mut Window,
19466        cx: &mut Context<Self>,
19467    ) {
19468        self.do_stage_or_unstage_and_next(false, window, cx);
19469    }
19470
19471    pub fn stage_or_unstage_diff_hunks(
19472        &mut self,
19473        stage: bool,
19474        ranges: Vec<Range<Anchor>>,
19475        cx: &mut Context<Self>,
19476    ) {
19477        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19478        cx.spawn(async move |this, cx| {
19479            task.await?;
19480            this.update(cx, |this, cx| {
19481                let snapshot = this.buffer.read(cx).snapshot(cx);
19482                let chunk_by = this
19483                    .diff_hunks_in_ranges(&ranges, &snapshot)
19484                    .chunk_by(|hunk| hunk.buffer_id);
19485                for (buffer_id, hunks) in &chunk_by {
19486                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19487                }
19488            })
19489        })
19490        .detach_and_log_err(cx);
19491    }
19492
19493    fn save_buffers_for_ranges_if_needed(
19494        &mut self,
19495        ranges: &[Range<Anchor>],
19496        cx: &mut Context<Editor>,
19497    ) -> Task<Result<()>> {
19498        let multibuffer = self.buffer.read(cx);
19499        let snapshot = multibuffer.read(cx);
19500        let buffer_ids: HashSet<_> = ranges
19501            .iter()
19502            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19503            .collect();
19504        drop(snapshot);
19505
19506        let mut buffers = HashSet::default();
19507        for buffer_id in buffer_ids {
19508            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19509                let buffer = buffer_entity.read(cx);
19510                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19511                {
19512                    buffers.insert(buffer_entity);
19513                }
19514            }
19515        }
19516
19517        if let Some(project) = &self.project {
19518            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19519        } else {
19520            Task::ready(Ok(()))
19521        }
19522    }
19523
19524    fn do_stage_or_unstage_and_next(
19525        &mut self,
19526        stage: bool,
19527        window: &mut Window,
19528        cx: &mut Context<Self>,
19529    ) {
19530        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19531
19532        if ranges.iter().any(|range| range.start != range.end) {
19533            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19534            return;
19535        }
19536
19537        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19538        let snapshot = self.snapshot(window, cx);
19539        let position = self
19540            .selections
19541            .newest::<Point>(&snapshot.display_snapshot)
19542            .head();
19543        let mut row = snapshot
19544            .buffer_snapshot()
19545            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19546            .find(|hunk| hunk.row_range.start.0 > position.row)
19547            .map(|hunk| hunk.row_range.start);
19548
19549        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19550        // Outside of the project diff editor, wrap around to the beginning.
19551        if !all_diff_hunks_expanded {
19552            row = row.or_else(|| {
19553                snapshot
19554                    .buffer_snapshot()
19555                    .diff_hunks_in_range(Point::zero()..position)
19556                    .find(|hunk| hunk.row_range.end.0 < position.row)
19557                    .map(|hunk| hunk.row_range.start)
19558            });
19559        }
19560
19561        if let Some(row) = row {
19562            let destination = Point::new(row.0, 0);
19563            let autoscroll = Autoscroll::center();
19564
19565            self.unfold_ranges(&[destination..destination], false, false, cx);
19566            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19567                s.select_ranges([destination..destination]);
19568            });
19569        }
19570    }
19571
19572    fn do_stage_or_unstage(
19573        &self,
19574        stage: bool,
19575        buffer_id: BufferId,
19576        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19577        cx: &mut App,
19578    ) -> Option<()> {
19579        let project = self.project()?;
19580        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19581        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19582        let buffer_snapshot = buffer.read(cx).snapshot();
19583        let file_exists = buffer_snapshot
19584            .file()
19585            .is_some_and(|file| file.disk_state().exists());
19586        diff.update(cx, |diff, cx| {
19587            diff.stage_or_unstage_hunks(
19588                stage,
19589                &hunks
19590                    .map(|hunk| buffer_diff::DiffHunk {
19591                        buffer_range: hunk.buffer_range,
19592                        // We don't need to pass in word diffs here because they're only used for rendering and
19593                        // this function changes internal state
19594                        base_word_diffs: Vec::default(),
19595                        buffer_word_diffs: Vec::default(),
19596                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19597                            ..hunk.diff_base_byte_range.end.0,
19598                        secondary_status: hunk.secondary_status,
19599                        range: Point::zero()..Point::zero(), // unused
19600                    })
19601                    .collect::<Vec<_>>(),
19602                &buffer_snapshot,
19603                file_exists,
19604                cx,
19605            )
19606        });
19607        None
19608    }
19609
19610    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19611        let ranges: Vec<_> = self
19612            .selections
19613            .disjoint_anchors()
19614            .iter()
19615            .map(|s| s.range())
19616            .collect();
19617        self.buffer
19618            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19619    }
19620
19621    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19622        self.buffer.update(cx, |buffer, cx| {
19623            let ranges = vec![Anchor::min()..Anchor::max()];
19624            if !buffer.all_diff_hunks_expanded()
19625                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19626            {
19627                buffer.collapse_diff_hunks(ranges, cx);
19628                true
19629            } else {
19630                false
19631            }
19632        })
19633    }
19634
19635    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19636        if self.buffer.read(cx).all_diff_hunks_expanded() {
19637            return true;
19638        }
19639        let ranges = vec![Anchor::min()..Anchor::max()];
19640        self.buffer
19641            .read(cx)
19642            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19643    }
19644
19645    fn toggle_diff_hunks_in_ranges(
19646        &mut self,
19647        ranges: Vec<Range<Anchor>>,
19648        cx: &mut Context<Editor>,
19649    ) {
19650        self.buffer.update(cx, |buffer, cx| {
19651            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19652            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19653        })
19654    }
19655
19656    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19657        self.buffer.update(cx, |buffer, cx| {
19658            let snapshot = buffer.snapshot(cx);
19659            let excerpt_id = range.end.excerpt_id;
19660            let point_range = range.to_point(&snapshot);
19661            let expand = !buffer.single_hunk_is_expanded(range, cx);
19662            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19663        })
19664    }
19665
19666    pub(crate) fn apply_all_diff_hunks(
19667        &mut self,
19668        _: &ApplyAllDiffHunks,
19669        window: &mut Window,
19670        cx: &mut Context<Self>,
19671    ) {
19672        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19673
19674        let buffers = self.buffer.read(cx).all_buffers();
19675        for branch_buffer in buffers {
19676            branch_buffer.update(cx, |branch_buffer, cx| {
19677                branch_buffer.merge_into_base(Vec::new(), cx);
19678            });
19679        }
19680
19681        if let Some(project) = self.project.clone() {
19682            self.save(
19683                SaveOptions {
19684                    format: true,
19685                    autosave: false,
19686                },
19687                project,
19688                window,
19689                cx,
19690            )
19691            .detach_and_log_err(cx);
19692        }
19693    }
19694
19695    pub(crate) fn apply_selected_diff_hunks(
19696        &mut self,
19697        _: &ApplyDiffHunk,
19698        window: &mut Window,
19699        cx: &mut Context<Self>,
19700    ) {
19701        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19702        let snapshot = self.snapshot(window, cx);
19703        let hunks = snapshot.hunks_for_ranges(
19704            self.selections
19705                .all(&snapshot.display_snapshot)
19706                .into_iter()
19707                .map(|selection| selection.range()),
19708        );
19709        let mut ranges_by_buffer = HashMap::default();
19710        self.transact(window, cx, |editor, _window, cx| {
19711            for hunk in hunks {
19712                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19713                    ranges_by_buffer
19714                        .entry(buffer.clone())
19715                        .or_insert_with(Vec::new)
19716                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19717                }
19718            }
19719
19720            for (buffer, ranges) in ranges_by_buffer {
19721                buffer.update(cx, |buffer, cx| {
19722                    buffer.merge_into_base(ranges, cx);
19723                });
19724            }
19725        });
19726
19727        if let Some(project) = self.project.clone() {
19728            self.save(
19729                SaveOptions {
19730                    format: true,
19731                    autosave: false,
19732                },
19733                project,
19734                window,
19735                cx,
19736            )
19737            .detach_and_log_err(cx);
19738        }
19739    }
19740
19741    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19742        if hovered != self.gutter_hovered {
19743            self.gutter_hovered = hovered;
19744            cx.notify();
19745        }
19746    }
19747
19748    pub fn insert_blocks(
19749        &mut self,
19750        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19751        autoscroll: Option<Autoscroll>,
19752        cx: &mut Context<Self>,
19753    ) -> Vec<CustomBlockId> {
19754        let blocks = self
19755            .display_map
19756            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19757        if let Some(autoscroll) = autoscroll {
19758            self.request_autoscroll(autoscroll, cx);
19759        }
19760        cx.notify();
19761        blocks
19762    }
19763
19764    pub fn resize_blocks(
19765        &mut self,
19766        heights: HashMap<CustomBlockId, u32>,
19767        autoscroll: Option<Autoscroll>,
19768        cx: &mut Context<Self>,
19769    ) {
19770        self.display_map
19771            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19772        if let Some(autoscroll) = autoscroll {
19773            self.request_autoscroll(autoscroll, cx);
19774        }
19775        cx.notify();
19776    }
19777
19778    pub fn replace_blocks(
19779        &mut self,
19780        renderers: HashMap<CustomBlockId, RenderBlock>,
19781        autoscroll: Option<Autoscroll>,
19782        cx: &mut Context<Self>,
19783    ) {
19784        self.display_map
19785            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19786        if let Some(autoscroll) = autoscroll {
19787            self.request_autoscroll(autoscroll, cx);
19788        }
19789        cx.notify();
19790    }
19791
19792    pub fn remove_blocks(
19793        &mut self,
19794        block_ids: HashSet<CustomBlockId>,
19795        autoscroll: Option<Autoscroll>,
19796        cx: &mut Context<Self>,
19797    ) {
19798        self.display_map.update(cx, |display_map, cx| {
19799            display_map.remove_blocks(block_ids, cx)
19800        });
19801        if let Some(autoscroll) = autoscroll {
19802            self.request_autoscroll(autoscroll, cx);
19803        }
19804        cx.notify();
19805    }
19806
19807    pub fn row_for_block(
19808        &self,
19809        block_id: CustomBlockId,
19810        cx: &mut Context<Self>,
19811    ) -> Option<DisplayRow> {
19812        self.display_map
19813            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19814    }
19815
19816    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19817        self.focused_block = Some(focused_block);
19818    }
19819
19820    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19821        self.focused_block.take()
19822    }
19823
19824    pub fn insert_creases(
19825        &mut self,
19826        creases: impl IntoIterator<Item = Crease<Anchor>>,
19827        cx: &mut Context<Self>,
19828    ) -> Vec<CreaseId> {
19829        self.display_map
19830            .update(cx, |map, cx| map.insert_creases(creases, cx))
19831    }
19832
19833    pub fn remove_creases(
19834        &mut self,
19835        ids: impl IntoIterator<Item = CreaseId>,
19836        cx: &mut Context<Self>,
19837    ) -> Vec<(CreaseId, Range<Anchor>)> {
19838        self.display_map
19839            .update(cx, |map, cx| map.remove_creases(ids, cx))
19840    }
19841
19842    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19843        self.display_map
19844            .update(cx, |map, cx| map.snapshot(cx))
19845            .longest_row()
19846    }
19847
19848    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19849        self.display_map
19850            .update(cx, |map, cx| map.snapshot(cx))
19851            .max_point()
19852    }
19853
19854    pub fn text(&self, cx: &App) -> String {
19855        self.buffer.read(cx).read(cx).text()
19856    }
19857
19858    pub fn is_empty(&self, cx: &App) -> bool {
19859        self.buffer.read(cx).read(cx).is_empty()
19860    }
19861
19862    pub fn text_option(&self, cx: &App) -> Option<String> {
19863        let text = self.text(cx);
19864        let text = text.trim();
19865
19866        if text.is_empty() {
19867            return None;
19868        }
19869
19870        Some(text.to_string())
19871    }
19872
19873    pub fn set_text(
19874        &mut self,
19875        text: impl Into<Arc<str>>,
19876        window: &mut Window,
19877        cx: &mut Context<Self>,
19878    ) {
19879        self.transact(window, cx, |this, _, cx| {
19880            this.buffer
19881                .read(cx)
19882                .as_singleton()
19883                .expect("you can only call set_text on editors for singleton buffers")
19884                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19885        });
19886    }
19887
19888    pub fn display_text(&self, cx: &mut App) -> String {
19889        self.display_map
19890            .update(cx, |map, cx| map.snapshot(cx))
19891            .text()
19892    }
19893
19894    fn create_minimap(
19895        &self,
19896        minimap_settings: MinimapSettings,
19897        window: &mut Window,
19898        cx: &mut Context<Self>,
19899    ) -> Option<Entity<Self>> {
19900        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19901            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19902    }
19903
19904    fn initialize_new_minimap(
19905        &self,
19906        minimap_settings: MinimapSettings,
19907        window: &mut Window,
19908        cx: &mut Context<Self>,
19909    ) -> Entity<Self> {
19910        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19911
19912        let mut minimap = Editor::new_internal(
19913            EditorMode::Minimap {
19914                parent: cx.weak_entity(),
19915            },
19916            self.buffer.clone(),
19917            None,
19918            Some(self.display_map.clone()),
19919            window,
19920            cx,
19921        );
19922        minimap.scroll_manager.clone_state(&self.scroll_manager);
19923        minimap.set_text_style_refinement(TextStyleRefinement {
19924            font_size: Some(MINIMAP_FONT_SIZE),
19925            font_weight: Some(MINIMAP_FONT_WEIGHT),
19926            ..Default::default()
19927        });
19928        minimap.update_minimap_configuration(minimap_settings, cx);
19929        cx.new(|_| minimap)
19930    }
19931
19932    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19933        let current_line_highlight = minimap_settings
19934            .current_line_highlight
19935            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19936        self.set_current_line_highlight(Some(current_line_highlight));
19937    }
19938
19939    pub fn minimap(&self) -> Option<&Entity<Self>> {
19940        self.minimap
19941            .as_ref()
19942            .filter(|_| self.minimap_visibility.visible())
19943    }
19944
19945    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19946        let mut wrap_guides = smallvec![];
19947
19948        if self.show_wrap_guides == Some(false) {
19949            return wrap_guides;
19950        }
19951
19952        let settings = self.buffer.read(cx).language_settings(cx);
19953        if settings.show_wrap_guides {
19954            match self.soft_wrap_mode(cx) {
19955                SoftWrap::Column(soft_wrap) => {
19956                    wrap_guides.push((soft_wrap as usize, true));
19957                }
19958                SoftWrap::Bounded(soft_wrap) => {
19959                    wrap_guides.push((soft_wrap as usize, true));
19960                }
19961                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19962            }
19963            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19964        }
19965
19966        wrap_guides
19967    }
19968
19969    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19970        let settings = self.buffer.read(cx).language_settings(cx);
19971        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19972        match mode {
19973            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19974                SoftWrap::None
19975            }
19976            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19977            language_settings::SoftWrap::PreferredLineLength => {
19978                SoftWrap::Column(settings.preferred_line_length)
19979            }
19980            language_settings::SoftWrap::Bounded => {
19981                SoftWrap::Bounded(settings.preferred_line_length)
19982            }
19983        }
19984    }
19985
19986    pub fn set_soft_wrap_mode(
19987        &mut self,
19988        mode: language_settings::SoftWrap,
19989
19990        cx: &mut Context<Self>,
19991    ) {
19992        self.soft_wrap_mode_override = Some(mode);
19993        cx.notify();
19994    }
19995
19996    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19997        self.hard_wrap = hard_wrap;
19998        cx.notify();
19999    }
20000
20001    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20002        self.text_style_refinement = Some(style);
20003    }
20004
20005    /// called by the Element so we know what style we were most recently rendered with.
20006    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20007        // We intentionally do not inform the display map about the minimap style
20008        // so that wrapping is not recalculated and stays consistent for the editor
20009        // and its linked minimap.
20010        if !self.mode.is_minimap() {
20011            let font = style.text.font();
20012            let font_size = style.text.font_size.to_pixels(window.rem_size());
20013            let display_map = self
20014                .placeholder_display_map
20015                .as_ref()
20016                .filter(|_| self.is_empty(cx))
20017                .unwrap_or(&self.display_map);
20018
20019            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20020        }
20021        self.style = Some(style);
20022    }
20023
20024    pub fn style(&self) -> Option<&EditorStyle> {
20025        self.style.as_ref()
20026    }
20027
20028    // Called by the element. This method is not designed to be called outside of the editor
20029    // element's layout code because it does not notify when rewrapping is computed synchronously.
20030    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20031        if self.is_empty(cx) {
20032            self.placeholder_display_map
20033                .as_ref()
20034                .map_or(false, |display_map| {
20035                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20036                })
20037        } else {
20038            self.display_map
20039                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20040        }
20041    }
20042
20043    pub fn set_soft_wrap(&mut self) {
20044        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20045    }
20046
20047    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20048        if self.soft_wrap_mode_override.is_some() {
20049            self.soft_wrap_mode_override.take();
20050        } else {
20051            let soft_wrap = match self.soft_wrap_mode(cx) {
20052                SoftWrap::GitDiff => return,
20053                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20054                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20055                    language_settings::SoftWrap::None
20056                }
20057            };
20058            self.soft_wrap_mode_override = Some(soft_wrap);
20059        }
20060        cx.notify();
20061    }
20062
20063    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20064        let Some(workspace) = self.workspace() else {
20065            return;
20066        };
20067        let fs = workspace.read(cx).app_state().fs.clone();
20068        let current_show = TabBarSettings::get_global(cx).show;
20069        update_settings_file(fs, cx, move |setting, _| {
20070            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20071        });
20072    }
20073
20074    pub fn toggle_indent_guides(
20075        &mut self,
20076        _: &ToggleIndentGuides,
20077        _: &mut Window,
20078        cx: &mut Context<Self>,
20079    ) {
20080        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20081            self.buffer
20082                .read(cx)
20083                .language_settings(cx)
20084                .indent_guides
20085                .enabled
20086        });
20087        self.show_indent_guides = Some(!currently_enabled);
20088        cx.notify();
20089    }
20090
20091    fn should_show_indent_guides(&self) -> Option<bool> {
20092        self.show_indent_guides
20093    }
20094
20095    pub fn disable_indent_guides_for_buffer(
20096        &mut self,
20097        buffer_id: BufferId,
20098        cx: &mut Context<Self>,
20099    ) {
20100        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20101        cx.notify();
20102    }
20103
20104    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20105        self.buffers_with_disabled_indent_guides
20106            .contains(&buffer_id)
20107    }
20108
20109    pub fn toggle_line_numbers(
20110        &mut self,
20111        _: &ToggleLineNumbers,
20112        _: &mut Window,
20113        cx: &mut Context<Self>,
20114    ) {
20115        let mut editor_settings = EditorSettings::get_global(cx).clone();
20116        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20117        EditorSettings::override_global(editor_settings, cx);
20118    }
20119
20120    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20121        if let Some(show_line_numbers) = self.show_line_numbers {
20122            return show_line_numbers;
20123        }
20124        EditorSettings::get_global(cx).gutter.line_numbers
20125    }
20126
20127    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20128        match (
20129            self.use_relative_line_numbers,
20130            EditorSettings::get_global(cx).relative_line_numbers,
20131        ) {
20132            (None, setting) => setting,
20133            (Some(false), _) => RelativeLineNumbers::Disabled,
20134            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20135            (Some(true), _) => RelativeLineNumbers::Enabled,
20136        }
20137    }
20138
20139    pub fn toggle_relative_line_numbers(
20140        &mut self,
20141        _: &ToggleRelativeLineNumbers,
20142        _: &mut Window,
20143        cx: &mut Context<Self>,
20144    ) {
20145        let is_relative = self.relative_line_numbers(cx);
20146        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20147    }
20148
20149    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20150        self.use_relative_line_numbers = is_relative;
20151        cx.notify();
20152    }
20153
20154    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20155        self.show_gutter = show_gutter;
20156        cx.notify();
20157    }
20158
20159    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20160        self.show_scrollbars = ScrollbarAxes {
20161            horizontal: show,
20162            vertical: show,
20163        };
20164        cx.notify();
20165    }
20166
20167    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20168        self.show_scrollbars.vertical = show;
20169        cx.notify();
20170    }
20171
20172    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20173        self.show_scrollbars.horizontal = show;
20174        cx.notify();
20175    }
20176
20177    pub fn set_minimap_visibility(
20178        &mut self,
20179        minimap_visibility: MinimapVisibility,
20180        window: &mut Window,
20181        cx: &mut Context<Self>,
20182    ) {
20183        if self.minimap_visibility != minimap_visibility {
20184            if minimap_visibility.visible() && self.minimap.is_none() {
20185                let minimap_settings = EditorSettings::get_global(cx).minimap;
20186                self.minimap =
20187                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20188            }
20189            self.minimap_visibility = minimap_visibility;
20190            cx.notify();
20191        }
20192    }
20193
20194    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20195        self.set_show_scrollbars(false, cx);
20196        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20197    }
20198
20199    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20200        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20201    }
20202
20203    /// Normally the text in full mode and auto height editors is padded on the
20204    /// left side by roughly half a character width for improved hit testing.
20205    ///
20206    /// Use this method to disable this for cases where this is not wanted (e.g.
20207    /// if you want to align the editor text with some other text above or below)
20208    /// or if you want to add this padding to single-line editors.
20209    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20210        self.offset_content = offset_content;
20211        cx.notify();
20212    }
20213
20214    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20215        self.show_line_numbers = Some(show_line_numbers);
20216        cx.notify();
20217    }
20218
20219    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20220        self.disable_expand_excerpt_buttons = true;
20221        cx.notify();
20222    }
20223
20224    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20225        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20226        cx.notify();
20227    }
20228
20229    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20230        self.show_code_actions = Some(show_code_actions);
20231        cx.notify();
20232    }
20233
20234    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20235        self.show_runnables = Some(show_runnables);
20236        cx.notify();
20237    }
20238
20239    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20240        self.show_breakpoints = Some(show_breakpoints);
20241        cx.notify();
20242    }
20243
20244    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20245        if self.display_map.read(cx).masked != masked {
20246            self.display_map.update(cx, |map, _| map.masked = masked);
20247        }
20248        cx.notify()
20249    }
20250
20251    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20252        self.show_wrap_guides = Some(show_wrap_guides);
20253        cx.notify();
20254    }
20255
20256    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20257        self.show_indent_guides = Some(show_indent_guides);
20258        cx.notify();
20259    }
20260
20261    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20262        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20263            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20264                && let Some(dir) = file.abs_path(cx).parent()
20265            {
20266                return Some(dir.to_owned());
20267            }
20268        }
20269
20270        None
20271    }
20272
20273    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20274        self.active_excerpt(cx)?
20275            .1
20276            .read(cx)
20277            .file()
20278            .and_then(|f| f.as_local())
20279    }
20280
20281    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20282        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20283            let buffer = buffer.read(cx);
20284            if let Some(project_path) = buffer.project_path(cx) {
20285                let project = self.project()?.read(cx);
20286                project.absolute_path(&project_path, cx)
20287            } else {
20288                buffer
20289                    .file()
20290                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20291            }
20292        })
20293    }
20294
20295    pub fn reveal_in_finder(
20296        &mut self,
20297        _: &RevealInFileManager,
20298        _window: &mut Window,
20299        cx: &mut Context<Self>,
20300    ) {
20301        if let Some(target) = self.target_file(cx) {
20302            cx.reveal_path(&target.abs_path(cx));
20303        }
20304    }
20305
20306    pub fn copy_path(
20307        &mut self,
20308        _: &zed_actions::workspace::CopyPath,
20309        _window: &mut Window,
20310        cx: &mut Context<Self>,
20311    ) {
20312        if let Some(path) = self.target_file_abs_path(cx)
20313            && let Some(path) = path.to_str()
20314        {
20315            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20316        } else {
20317            cx.propagate();
20318        }
20319    }
20320
20321    pub fn copy_relative_path(
20322        &mut self,
20323        _: &zed_actions::workspace::CopyRelativePath,
20324        _window: &mut Window,
20325        cx: &mut Context<Self>,
20326    ) {
20327        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20328            let project = self.project()?.read(cx);
20329            let path = buffer.read(cx).file()?.path();
20330            let path = path.display(project.path_style(cx));
20331            Some(path)
20332        }) {
20333            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20334        } else {
20335            cx.propagate();
20336        }
20337    }
20338
20339    /// Returns the project path for the editor's buffer, if any buffer is
20340    /// opened in the editor.
20341    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20342        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20343            buffer.read(cx).project_path(cx)
20344        } else {
20345            None
20346        }
20347    }
20348
20349    // Returns true if the editor handled a go-to-line request
20350    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20351        maybe!({
20352            let breakpoint_store = self.breakpoint_store.as_ref()?;
20353
20354            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20355            else {
20356                self.clear_row_highlights::<ActiveDebugLine>();
20357                return None;
20358            };
20359
20360            let position = active_stack_frame.position;
20361            let buffer_id = position.buffer_id?;
20362            let snapshot = self
20363                .project
20364                .as_ref()?
20365                .read(cx)
20366                .buffer_for_id(buffer_id, cx)?
20367                .read(cx)
20368                .snapshot();
20369
20370            let mut handled = false;
20371            for (id, ExcerptRange { context, .. }) in
20372                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20373            {
20374                if context.start.cmp(&position, &snapshot).is_ge()
20375                    || context.end.cmp(&position, &snapshot).is_lt()
20376                {
20377                    continue;
20378                }
20379                let snapshot = self.buffer.read(cx).snapshot(cx);
20380                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20381
20382                handled = true;
20383                self.clear_row_highlights::<ActiveDebugLine>();
20384
20385                self.go_to_line::<ActiveDebugLine>(
20386                    multibuffer_anchor,
20387                    Some(cx.theme().colors().editor_debugger_active_line_background),
20388                    window,
20389                    cx,
20390                );
20391
20392                cx.notify();
20393            }
20394
20395            handled.then_some(())
20396        })
20397        .is_some()
20398    }
20399
20400    pub fn copy_file_name_without_extension(
20401        &mut self,
20402        _: &CopyFileNameWithoutExtension,
20403        _: &mut Window,
20404        cx: &mut Context<Self>,
20405    ) {
20406        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20407            let file = buffer.read(cx).file()?;
20408            file.path().file_stem()
20409        }) {
20410            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20411        }
20412    }
20413
20414    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20415        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20416            let file = buffer.read(cx).file()?;
20417            Some(file.file_name(cx))
20418        }) {
20419            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20420        }
20421    }
20422
20423    pub fn toggle_git_blame(
20424        &mut self,
20425        _: &::git::Blame,
20426        window: &mut Window,
20427        cx: &mut Context<Self>,
20428    ) {
20429        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20430
20431        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20432            self.start_git_blame(true, window, cx);
20433        }
20434
20435        cx.notify();
20436    }
20437
20438    pub fn toggle_git_blame_inline(
20439        &mut self,
20440        _: &ToggleGitBlameInline,
20441        window: &mut Window,
20442        cx: &mut Context<Self>,
20443    ) {
20444        self.toggle_git_blame_inline_internal(true, window, cx);
20445        cx.notify();
20446    }
20447
20448    pub fn open_git_blame_commit(
20449        &mut self,
20450        _: &OpenGitBlameCommit,
20451        window: &mut Window,
20452        cx: &mut Context<Self>,
20453    ) {
20454        self.open_git_blame_commit_internal(window, cx);
20455    }
20456
20457    fn open_git_blame_commit_internal(
20458        &mut self,
20459        window: &mut Window,
20460        cx: &mut Context<Self>,
20461    ) -> Option<()> {
20462        let blame = self.blame.as_ref()?;
20463        let snapshot = self.snapshot(window, cx);
20464        let cursor = self
20465            .selections
20466            .newest::<Point>(&snapshot.display_snapshot)
20467            .head();
20468        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20469        let (_, blame_entry) = blame
20470            .update(cx, |blame, cx| {
20471                blame
20472                    .blame_for_rows(
20473                        &[RowInfo {
20474                            buffer_id: Some(buffer.remote_id()),
20475                            buffer_row: Some(point.row),
20476                            ..Default::default()
20477                        }],
20478                        cx,
20479                    )
20480                    .next()
20481            })
20482            .flatten()?;
20483        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20484        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20485        let workspace = self.workspace()?.downgrade();
20486        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20487        None
20488    }
20489
20490    pub fn git_blame_inline_enabled(&self) -> bool {
20491        self.git_blame_inline_enabled
20492    }
20493
20494    pub fn toggle_selection_menu(
20495        &mut self,
20496        _: &ToggleSelectionMenu,
20497        _: &mut Window,
20498        cx: &mut Context<Self>,
20499    ) {
20500        self.show_selection_menu = self
20501            .show_selection_menu
20502            .map(|show_selections_menu| !show_selections_menu)
20503            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20504
20505        cx.notify();
20506    }
20507
20508    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20509        self.show_selection_menu
20510            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20511    }
20512
20513    fn start_git_blame(
20514        &mut self,
20515        user_triggered: bool,
20516        window: &mut Window,
20517        cx: &mut Context<Self>,
20518    ) {
20519        if let Some(project) = self.project() {
20520            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20521                && buffer.read(cx).file().is_none()
20522            {
20523                return;
20524            }
20525
20526            let focused = self.focus_handle(cx).contains_focused(window, cx);
20527
20528            let project = project.clone();
20529            let blame = cx
20530                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20531            self.blame_subscription =
20532                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20533            self.blame = Some(blame);
20534        }
20535    }
20536
20537    fn toggle_git_blame_inline_internal(
20538        &mut self,
20539        user_triggered: bool,
20540        window: &mut Window,
20541        cx: &mut Context<Self>,
20542    ) {
20543        if self.git_blame_inline_enabled {
20544            self.git_blame_inline_enabled = false;
20545            self.show_git_blame_inline = false;
20546            self.show_git_blame_inline_delay_task.take();
20547        } else {
20548            self.git_blame_inline_enabled = true;
20549            self.start_git_blame_inline(user_triggered, window, cx);
20550        }
20551
20552        cx.notify();
20553    }
20554
20555    fn start_git_blame_inline(
20556        &mut self,
20557        user_triggered: bool,
20558        window: &mut Window,
20559        cx: &mut Context<Self>,
20560    ) {
20561        self.start_git_blame(user_triggered, window, cx);
20562
20563        if ProjectSettings::get_global(cx)
20564            .git
20565            .inline_blame_delay()
20566            .is_some()
20567        {
20568            self.start_inline_blame_timer(window, cx);
20569        } else {
20570            self.show_git_blame_inline = true
20571        }
20572    }
20573
20574    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20575        self.blame.as_ref()
20576    }
20577
20578    pub fn show_git_blame_gutter(&self) -> bool {
20579        self.show_git_blame_gutter
20580    }
20581
20582    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20583        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20584    }
20585
20586    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20587        self.show_git_blame_inline
20588            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20589            && !self.newest_selection_head_on_empty_line(cx)
20590            && self.has_blame_entries(cx)
20591    }
20592
20593    fn has_blame_entries(&self, cx: &App) -> bool {
20594        self.blame()
20595            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20596    }
20597
20598    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20599        let cursor_anchor = self.selections.newest_anchor().head();
20600
20601        let snapshot = self.buffer.read(cx).snapshot(cx);
20602        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20603
20604        snapshot.line_len(buffer_row) == 0
20605    }
20606
20607    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20608        let buffer_and_selection = maybe!({
20609            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20610            let selection_range = selection.range();
20611
20612            let multi_buffer = self.buffer().read(cx);
20613            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20614            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20615
20616            let (buffer, range, _) = if selection.reversed {
20617                buffer_ranges.first()
20618            } else {
20619                buffer_ranges.last()
20620            }?;
20621
20622            let selection = text::ToPoint::to_point(&range.start, buffer).row
20623                ..text::ToPoint::to_point(&range.end, buffer).row;
20624            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20625        });
20626
20627        let Some((buffer, selection)) = buffer_and_selection else {
20628            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20629        };
20630
20631        let Some(project) = self.project() else {
20632            return Task::ready(Err(anyhow!("editor does not have project")));
20633        };
20634
20635        project.update(cx, |project, cx| {
20636            project.get_permalink_to_line(&buffer, selection, cx)
20637        })
20638    }
20639
20640    pub fn copy_permalink_to_line(
20641        &mut self,
20642        _: &CopyPermalinkToLine,
20643        window: &mut Window,
20644        cx: &mut Context<Self>,
20645    ) {
20646        let permalink_task = self.get_permalink_to_line(cx);
20647        let workspace = self.workspace();
20648
20649        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20650            Ok(permalink) => {
20651                cx.update(|_, cx| {
20652                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20653                })
20654                .ok();
20655            }
20656            Err(err) => {
20657                let message = format!("Failed to copy permalink: {err}");
20658
20659                anyhow::Result::<()>::Err(err).log_err();
20660
20661                if let Some(workspace) = workspace {
20662                    workspace
20663                        .update_in(cx, |workspace, _, cx| {
20664                            struct CopyPermalinkToLine;
20665
20666                            workspace.show_toast(
20667                                Toast::new(
20668                                    NotificationId::unique::<CopyPermalinkToLine>(),
20669                                    message,
20670                                ),
20671                                cx,
20672                            )
20673                        })
20674                        .ok();
20675                }
20676            }
20677        })
20678        .detach();
20679    }
20680
20681    pub fn copy_file_location(
20682        &mut self,
20683        _: &CopyFileLocation,
20684        _: &mut Window,
20685        cx: &mut Context<Self>,
20686    ) {
20687        let selection = self
20688            .selections
20689            .newest::<Point>(&self.display_snapshot(cx))
20690            .start
20691            .row
20692            + 1;
20693        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20694            let project = self.project()?.read(cx);
20695            let file = buffer.read(cx).file()?;
20696            let path = file.path().display(project.path_style(cx));
20697
20698            Some(format!("{path}:{selection}"))
20699        }) {
20700            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
20701        }
20702    }
20703
20704    pub fn open_permalink_to_line(
20705        &mut self,
20706        _: &OpenPermalinkToLine,
20707        window: &mut Window,
20708        cx: &mut Context<Self>,
20709    ) {
20710        let permalink_task = self.get_permalink_to_line(cx);
20711        let workspace = self.workspace();
20712
20713        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20714            Ok(permalink) => {
20715                cx.update(|_, cx| {
20716                    cx.open_url(permalink.as_ref());
20717                })
20718                .ok();
20719            }
20720            Err(err) => {
20721                let message = format!("Failed to open permalink: {err}");
20722
20723                anyhow::Result::<()>::Err(err).log_err();
20724
20725                if let Some(workspace) = workspace {
20726                    workspace
20727                        .update(cx, |workspace, cx| {
20728                            struct OpenPermalinkToLine;
20729
20730                            workspace.show_toast(
20731                                Toast::new(
20732                                    NotificationId::unique::<OpenPermalinkToLine>(),
20733                                    message,
20734                                ),
20735                                cx,
20736                            )
20737                        })
20738                        .ok();
20739                }
20740            }
20741        })
20742        .detach();
20743    }
20744
20745    pub fn insert_uuid_v4(
20746        &mut self,
20747        _: &InsertUuidV4,
20748        window: &mut Window,
20749        cx: &mut Context<Self>,
20750    ) {
20751        self.insert_uuid(UuidVersion::V4, window, cx);
20752    }
20753
20754    pub fn insert_uuid_v7(
20755        &mut self,
20756        _: &InsertUuidV7,
20757        window: &mut Window,
20758        cx: &mut Context<Self>,
20759    ) {
20760        self.insert_uuid(UuidVersion::V7, window, cx);
20761    }
20762
20763    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20764        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20765        self.transact(window, cx, |this, window, cx| {
20766            let edits = this
20767                .selections
20768                .all::<Point>(&this.display_snapshot(cx))
20769                .into_iter()
20770                .map(|selection| {
20771                    let uuid = match version {
20772                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20773                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20774                    };
20775
20776                    (selection.range(), uuid.to_string())
20777                });
20778            this.edit(edits, cx);
20779            this.refresh_edit_prediction(true, false, window, cx);
20780        });
20781    }
20782
20783    pub fn open_selections_in_multibuffer(
20784        &mut self,
20785        _: &OpenSelectionsInMultibuffer,
20786        window: &mut Window,
20787        cx: &mut Context<Self>,
20788    ) {
20789        let multibuffer = self.buffer.read(cx);
20790
20791        let Some(buffer) = multibuffer.as_singleton() else {
20792            return;
20793        };
20794
20795        let Some(workspace) = self.workspace() else {
20796            return;
20797        };
20798
20799        let title = multibuffer.title(cx).to_string();
20800
20801        let locations = self
20802            .selections
20803            .all_anchors(&self.display_snapshot(cx))
20804            .iter()
20805            .map(|selection| {
20806                (
20807                    buffer.clone(),
20808                    (selection.start.text_anchor..selection.end.text_anchor)
20809                        .to_point(buffer.read(cx)),
20810                )
20811            })
20812            .into_group_map();
20813
20814        cx.spawn_in(window, async move |_, cx| {
20815            workspace.update_in(cx, |workspace, window, cx| {
20816                Self::open_locations_in_multibuffer(
20817                    workspace,
20818                    locations,
20819                    format!("Selections for '{title}'"),
20820                    false,
20821                    false,
20822                    MultibufferSelectionMode::All,
20823                    window,
20824                    cx,
20825                );
20826            })
20827        })
20828        .detach();
20829    }
20830
20831    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20832    /// last highlight added will be used.
20833    ///
20834    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20835    pub fn highlight_rows<T: 'static>(
20836        &mut self,
20837        range: Range<Anchor>,
20838        color: Hsla,
20839        options: RowHighlightOptions,
20840        cx: &mut Context<Self>,
20841    ) {
20842        let snapshot = self.buffer().read(cx).snapshot(cx);
20843        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20844        let ix = row_highlights.binary_search_by(|highlight| {
20845            Ordering::Equal
20846                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20847                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20848        });
20849
20850        if let Err(mut ix) = ix {
20851            let index = post_inc(&mut self.highlight_order);
20852
20853            // If this range intersects with the preceding highlight, then merge it with
20854            // the preceding highlight. Otherwise insert a new highlight.
20855            let mut merged = false;
20856            if ix > 0 {
20857                let prev_highlight = &mut row_highlights[ix - 1];
20858                if prev_highlight
20859                    .range
20860                    .end
20861                    .cmp(&range.start, &snapshot)
20862                    .is_ge()
20863                {
20864                    ix -= 1;
20865                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20866                        prev_highlight.range.end = range.end;
20867                    }
20868                    merged = true;
20869                    prev_highlight.index = index;
20870                    prev_highlight.color = color;
20871                    prev_highlight.options = options;
20872                }
20873            }
20874
20875            if !merged {
20876                row_highlights.insert(
20877                    ix,
20878                    RowHighlight {
20879                        range,
20880                        index,
20881                        color,
20882                        options,
20883                        type_id: TypeId::of::<T>(),
20884                    },
20885                );
20886            }
20887
20888            // If any of the following highlights intersect with this one, merge them.
20889            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20890                let highlight = &row_highlights[ix];
20891                if next_highlight
20892                    .range
20893                    .start
20894                    .cmp(&highlight.range.end, &snapshot)
20895                    .is_le()
20896                {
20897                    if next_highlight
20898                        .range
20899                        .end
20900                        .cmp(&highlight.range.end, &snapshot)
20901                        .is_gt()
20902                    {
20903                        row_highlights[ix].range.end = next_highlight.range.end;
20904                    }
20905                    row_highlights.remove(ix + 1);
20906                } else {
20907                    break;
20908                }
20909            }
20910        }
20911    }
20912
20913    /// Remove any highlighted row ranges of the given type that intersect the
20914    /// given ranges.
20915    pub fn remove_highlighted_rows<T: 'static>(
20916        &mut self,
20917        ranges_to_remove: Vec<Range<Anchor>>,
20918        cx: &mut Context<Self>,
20919    ) {
20920        let snapshot = self.buffer().read(cx).snapshot(cx);
20921        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20922        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20923        row_highlights.retain(|highlight| {
20924            while let Some(range_to_remove) = ranges_to_remove.peek() {
20925                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20926                    Ordering::Less | Ordering::Equal => {
20927                        ranges_to_remove.next();
20928                    }
20929                    Ordering::Greater => {
20930                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20931                            Ordering::Less | Ordering::Equal => {
20932                                return false;
20933                            }
20934                            Ordering::Greater => break,
20935                        }
20936                    }
20937                }
20938            }
20939
20940            true
20941        })
20942    }
20943
20944    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20945    pub fn clear_row_highlights<T: 'static>(&mut self) {
20946        self.highlighted_rows.remove(&TypeId::of::<T>());
20947    }
20948
20949    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20950    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20951        self.highlighted_rows
20952            .get(&TypeId::of::<T>())
20953            .map_or(&[] as &[_], |vec| vec.as_slice())
20954            .iter()
20955            .map(|highlight| (highlight.range.clone(), highlight.color))
20956    }
20957
20958    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20959    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20960    /// Allows to ignore certain kinds of highlights.
20961    pub fn highlighted_display_rows(
20962        &self,
20963        window: &mut Window,
20964        cx: &mut App,
20965    ) -> BTreeMap<DisplayRow, LineHighlight> {
20966        let snapshot = self.snapshot(window, cx);
20967        let mut used_highlight_orders = HashMap::default();
20968        self.highlighted_rows
20969            .iter()
20970            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20971            .fold(
20972                BTreeMap::<DisplayRow, LineHighlight>::new(),
20973                |mut unique_rows, highlight| {
20974                    let start = highlight.range.start.to_display_point(&snapshot);
20975                    let end = highlight.range.end.to_display_point(&snapshot);
20976                    let start_row = start.row().0;
20977                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
20978                    {
20979                        end.row().0.saturating_sub(1)
20980                    } else {
20981                        end.row().0
20982                    };
20983                    for row in start_row..=end_row {
20984                        let used_index =
20985                            used_highlight_orders.entry(row).or_insert(highlight.index);
20986                        if highlight.index >= *used_index {
20987                            *used_index = highlight.index;
20988                            unique_rows.insert(
20989                                DisplayRow(row),
20990                                LineHighlight {
20991                                    include_gutter: highlight.options.include_gutter,
20992                                    border: None,
20993                                    background: highlight.color.into(),
20994                                    type_id: Some(highlight.type_id),
20995                                },
20996                            );
20997                        }
20998                    }
20999                    unique_rows
21000                },
21001            )
21002    }
21003
21004    pub fn highlighted_display_row_for_autoscroll(
21005        &self,
21006        snapshot: &DisplaySnapshot,
21007    ) -> Option<DisplayRow> {
21008        self.highlighted_rows
21009            .values()
21010            .flat_map(|highlighted_rows| highlighted_rows.iter())
21011            .filter_map(|highlight| {
21012                if highlight.options.autoscroll {
21013                    Some(highlight.range.start.to_display_point(snapshot).row())
21014                } else {
21015                    None
21016                }
21017            })
21018            .min()
21019    }
21020
21021    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21022        self.highlight_background::<SearchWithinRange>(
21023            ranges,
21024            |_, colors| colors.colors().editor_document_highlight_read_background,
21025            cx,
21026        )
21027    }
21028
21029    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21030        self.breadcrumb_header = Some(new_header);
21031    }
21032
21033    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21034        self.clear_background_highlights::<SearchWithinRange>(cx);
21035    }
21036
21037    pub fn highlight_background<T: 'static>(
21038        &mut self,
21039        ranges: &[Range<Anchor>],
21040        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21041        cx: &mut Context<Self>,
21042    ) {
21043        self.background_highlights.insert(
21044            HighlightKey::Type(TypeId::of::<T>()),
21045            (Arc::new(color_fetcher), Arc::from(ranges)),
21046        );
21047        self.scrollbar_marker_state.dirty = true;
21048        cx.notify();
21049    }
21050
21051    pub fn highlight_background_key<T: 'static>(
21052        &mut self,
21053        key: usize,
21054        ranges: &[Range<Anchor>],
21055        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21056        cx: &mut Context<Self>,
21057    ) {
21058        self.background_highlights.insert(
21059            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21060            (Arc::new(color_fetcher), Arc::from(ranges)),
21061        );
21062        self.scrollbar_marker_state.dirty = true;
21063        cx.notify();
21064    }
21065
21066    pub fn clear_background_highlights<T: 'static>(
21067        &mut self,
21068        cx: &mut Context<Self>,
21069    ) -> Option<BackgroundHighlight> {
21070        let text_highlights = self
21071            .background_highlights
21072            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21073        if !text_highlights.1.is_empty() {
21074            self.scrollbar_marker_state.dirty = true;
21075            cx.notify();
21076        }
21077        Some(text_highlights)
21078    }
21079
21080    pub fn highlight_gutter<T: 'static>(
21081        &mut self,
21082        ranges: impl Into<Vec<Range<Anchor>>>,
21083        color_fetcher: fn(&App) -> Hsla,
21084        cx: &mut Context<Self>,
21085    ) {
21086        self.gutter_highlights
21087            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21088        cx.notify();
21089    }
21090
21091    pub fn clear_gutter_highlights<T: 'static>(
21092        &mut self,
21093        cx: &mut Context<Self>,
21094    ) -> Option<GutterHighlight> {
21095        cx.notify();
21096        self.gutter_highlights.remove(&TypeId::of::<T>())
21097    }
21098
21099    pub fn insert_gutter_highlight<T: 'static>(
21100        &mut self,
21101        range: Range<Anchor>,
21102        color_fetcher: fn(&App) -> Hsla,
21103        cx: &mut Context<Self>,
21104    ) {
21105        let snapshot = self.buffer().read(cx).snapshot(cx);
21106        let mut highlights = self
21107            .gutter_highlights
21108            .remove(&TypeId::of::<T>())
21109            .map(|(_, highlights)| highlights)
21110            .unwrap_or_default();
21111        let ix = highlights.binary_search_by(|highlight| {
21112            Ordering::Equal
21113                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21114                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21115        });
21116        if let Err(ix) = ix {
21117            highlights.insert(ix, range);
21118        }
21119        self.gutter_highlights
21120            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21121    }
21122
21123    pub fn remove_gutter_highlights<T: 'static>(
21124        &mut self,
21125        ranges_to_remove: Vec<Range<Anchor>>,
21126        cx: &mut Context<Self>,
21127    ) {
21128        let snapshot = self.buffer().read(cx).snapshot(cx);
21129        let Some((color_fetcher, mut gutter_highlights)) =
21130            self.gutter_highlights.remove(&TypeId::of::<T>())
21131        else {
21132            return;
21133        };
21134        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21135        gutter_highlights.retain(|highlight| {
21136            while let Some(range_to_remove) = ranges_to_remove.peek() {
21137                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21138                    Ordering::Less | Ordering::Equal => {
21139                        ranges_to_remove.next();
21140                    }
21141                    Ordering::Greater => {
21142                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21143                            Ordering::Less | Ordering::Equal => {
21144                                return false;
21145                            }
21146                            Ordering::Greater => break,
21147                        }
21148                    }
21149                }
21150            }
21151
21152            true
21153        });
21154        self.gutter_highlights
21155            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21156    }
21157
21158    #[cfg(feature = "test-support")]
21159    pub fn all_text_highlights(
21160        &self,
21161        window: &mut Window,
21162        cx: &mut Context<Self>,
21163    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21164        let snapshot = self.snapshot(window, cx);
21165        self.display_map.update(cx, |display_map, _| {
21166            display_map
21167                .all_text_highlights()
21168                .map(|highlight| {
21169                    let (style, ranges) = highlight.as_ref();
21170                    (
21171                        *style,
21172                        ranges
21173                            .iter()
21174                            .map(|range| range.clone().to_display_points(&snapshot))
21175                            .collect(),
21176                    )
21177                })
21178                .collect()
21179        })
21180    }
21181
21182    #[cfg(feature = "test-support")]
21183    pub fn all_text_background_highlights(
21184        &self,
21185        window: &mut Window,
21186        cx: &mut Context<Self>,
21187    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21188        let snapshot = self.snapshot(window, cx);
21189        let buffer = &snapshot.buffer_snapshot();
21190        let start = buffer.anchor_before(MultiBufferOffset(0));
21191        let end = buffer.anchor_after(buffer.len());
21192        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21193    }
21194
21195    #[cfg(any(test, feature = "test-support"))]
21196    pub fn sorted_background_highlights_in_range(
21197        &self,
21198        search_range: Range<Anchor>,
21199        display_snapshot: &DisplaySnapshot,
21200        theme: &Theme,
21201    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21202        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21203        res.sort_by(|a, b| {
21204            a.0.start
21205                .cmp(&b.0.start)
21206                .then_with(|| a.0.end.cmp(&b.0.end))
21207                .then_with(|| a.1.cmp(&b.1))
21208        });
21209        res
21210    }
21211
21212    #[cfg(feature = "test-support")]
21213    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21214        let snapshot = self.buffer().read(cx).snapshot(cx);
21215
21216        let highlights = self
21217            .background_highlights
21218            .get(&HighlightKey::Type(TypeId::of::<
21219                items::BufferSearchHighlights,
21220            >()));
21221
21222        if let Some((_color, ranges)) = highlights {
21223            ranges
21224                .iter()
21225                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21226                .collect_vec()
21227        } else {
21228            vec![]
21229        }
21230    }
21231
21232    fn document_highlights_for_position<'a>(
21233        &'a self,
21234        position: Anchor,
21235        buffer: &'a MultiBufferSnapshot,
21236    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21237        let read_highlights = self
21238            .background_highlights
21239            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21240            .map(|h| &h.1);
21241        let write_highlights = self
21242            .background_highlights
21243            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21244            .map(|h| &h.1);
21245        let left_position = position.bias_left(buffer);
21246        let right_position = position.bias_right(buffer);
21247        read_highlights
21248            .into_iter()
21249            .chain(write_highlights)
21250            .flat_map(move |ranges| {
21251                let start_ix = match ranges.binary_search_by(|probe| {
21252                    let cmp = probe.end.cmp(&left_position, buffer);
21253                    if cmp.is_ge() {
21254                        Ordering::Greater
21255                    } else {
21256                        Ordering::Less
21257                    }
21258                }) {
21259                    Ok(i) | Err(i) => i,
21260                };
21261
21262                ranges[start_ix..]
21263                    .iter()
21264                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21265            })
21266    }
21267
21268    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21269        self.background_highlights
21270            .get(&HighlightKey::Type(TypeId::of::<T>()))
21271            .is_some_and(|(_, highlights)| !highlights.is_empty())
21272    }
21273
21274    /// Returns all background highlights for a given range.
21275    ///
21276    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21277    pub fn background_highlights_in_range(
21278        &self,
21279        search_range: Range<Anchor>,
21280        display_snapshot: &DisplaySnapshot,
21281        theme: &Theme,
21282    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21283        let mut results = Vec::new();
21284        for (color_fetcher, ranges) in self.background_highlights.values() {
21285            let start_ix = match ranges.binary_search_by(|probe| {
21286                let cmp = probe
21287                    .end
21288                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21289                if cmp.is_gt() {
21290                    Ordering::Greater
21291                } else {
21292                    Ordering::Less
21293                }
21294            }) {
21295                Ok(i) | Err(i) => i,
21296            };
21297            for (index, range) in ranges[start_ix..].iter().enumerate() {
21298                if range
21299                    .start
21300                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21301                    .is_ge()
21302                {
21303                    break;
21304                }
21305
21306                let color = color_fetcher(&(start_ix + index), theme);
21307                let start = range.start.to_display_point(display_snapshot);
21308                let end = range.end.to_display_point(display_snapshot);
21309                results.push((start..end, color))
21310            }
21311        }
21312        results
21313    }
21314
21315    pub fn gutter_highlights_in_range(
21316        &self,
21317        search_range: Range<Anchor>,
21318        display_snapshot: &DisplaySnapshot,
21319        cx: &App,
21320    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21321        let mut results = Vec::new();
21322        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21323            let color = color_fetcher(cx);
21324            let start_ix = match ranges.binary_search_by(|probe| {
21325                let cmp = probe
21326                    .end
21327                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21328                if cmp.is_gt() {
21329                    Ordering::Greater
21330                } else {
21331                    Ordering::Less
21332                }
21333            }) {
21334                Ok(i) | Err(i) => i,
21335            };
21336            for range in &ranges[start_ix..] {
21337                if range
21338                    .start
21339                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21340                    .is_ge()
21341                {
21342                    break;
21343                }
21344
21345                let start = range.start.to_display_point(display_snapshot);
21346                let end = range.end.to_display_point(display_snapshot);
21347                results.push((start..end, color))
21348            }
21349        }
21350        results
21351    }
21352
21353    /// Get the text ranges corresponding to the redaction query
21354    pub fn redacted_ranges(
21355        &self,
21356        search_range: Range<Anchor>,
21357        display_snapshot: &DisplaySnapshot,
21358        cx: &App,
21359    ) -> Vec<Range<DisplayPoint>> {
21360        display_snapshot
21361            .buffer_snapshot()
21362            .redacted_ranges(search_range, |file| {
21363                if let Some(file) = file {
21364                    file.is_private()
21365                        && EditorSettings::get(
21366                            Some(SettingsLocation {
21367                                worktree_id: file.worktree_id(cx),
21368                                path: file.path().as_ref(),
21369                            }),
21370                            cx,
21371                        )
21372                        .redact_private_values
21373                } else {
21374                    false
21375                }
21376            })
21377            .map(|range| {
21378                range.start.to_display_point(display_snapshot)
21379                    ..range.end.to_display_point(display_snapshot)
21380            })
21381            .collect()
21382    }
21383
21384    pub fn highlight_text_key<T: 'static>(
21385        &mut self,
21386        key: usize,
21387        ranges: Vec<Range<Anchor>>,
21388        style: HighlightStyle,
21389        merge: bool,
21390        cx: &mut Context<Self>,
21391    ) {
21392        self.display_map.update(cx, |map, cx| {
21393            map.highlight_text(
21394                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21395                ranges,
21396                style,
21397                merge,
21398                cx,
21399            );
21400        });
21401        cx.notify();
21402    }
21403
21404    pub fn highlight_text<T: 'static>(
21405        &mut self,
21406        ranges: Vec<Range<Anchor>>,
21407        style: HighlightStyle,
21408        cx: &mut Context<Self>,
21409    ) {
21410        self.display_map.update(cx, |map, cx| {
21411            map.highlight_text(
21412                HighlightKey::Type(TypeId::of::<T>()),
21413                ranges,
21414                style,
21415                false,
21416                cx,
21417            )
21418        });
21419        cx.notify();
21420    }
21421
21422    pub fn text_highlights<'a, T: 'static>(
21423        &'a self,
21424        cx: &'a App,
21425    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21426        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21427    }
21428
21429    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21430        let cleared = self
21431            .display_map
21432            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21433        if cleared {
21434            cx.notify();
21435        }
21436    }
21437
21438    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21439        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21440            && self.focus_handle.is_focused(window)
21441    }
21442
21443    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21444        self.show_cursor_when_unfocused = is_enabled;
21445        cx.notify();
21446    }
21447
21448    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21449        cx.notify();
21450    }
21451
21452    fn on_debug_session_event(
21453        &mut self,
21454        _session: Entity<Session>,
21455        event: &SessionEvent,
21456        cx: &mut Context<Self>,
21457    ) {
21458        if let SessionEvent::InvalidateInlineValue = event {
21459            self.refresh_inline_values(cx);
21460        }
21461    }
21462
21463    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21464        let Some(project) = self.project.clone() else {
21465            return;
21466        };
21467
21468        if !self.inline_value_cache.enabled {
21469            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21470            self.splice_inlays(&inlays, Vec::new(), cx);
21471            return;
21472        }
21473
21474        let current_execution_position = self
21475            .highlighted_rows
21476            .get(&TypeId::of::<ActiveDebugLine>())
21477            .and_then(|lines| lines.last().map(|line| line.range.end));
21478
21479        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21480            let inline_values = editor
21481                .update(cx, |editor, cx| {
21482                    let Some(current_execution_position) = current_execution_position else {
21483                        return Some(Task::ready(Ok(Vec::new())));
21484                    };
21485
21486                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21487                        let snapshot = buffer.snapshot(cx);
21488
21489                        let excerpt = snapshot.excerpt_containing(
21490                            current_execution_position..current_execution_position,
21491                        )?;
21492
21493                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21494                    })?;
21495
21496                    let range =
21497                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21498
21499                    project.inline_values(buffer, range, cx)
21500                })
21501                .ok()
21502                .flatten()?
21503                .await
21504                .context("refreshing debugger inlays")
21505                .log_err()?;
21506
21507            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21508
21509            for (buffer_id, inline_value) in inline_values
21510                .into_iter()
21511                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21512            {
21513                buffer_inline_values
21514                    .entry(buffer_id)
21515                    .or_default()
21516                    .push(inline_value);
21517            }
21518
21519            editor
21520                .update(cx, |editor, cx| {
21521                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21522                    let mut new_inlays = Vec::default();
21523
21524                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21525                        let buffer_id = buffer_snapshot.remote_id();
21526                        buffer_inline_values
21527                            .get(&buffer_id)
21528                            .into_iter()
21529                            .flatten()
21530                            .for_each(|hint| {
21531                                let inlay = Inlay::debugger(
21532                                    post_inc(&mut editor.next_inlay_id),
21533                                    Anchor::in_buffer(excerpt_id, hint.position),
21534                                    hint.text(),
21535                                );
21536                                if !inlay.text().chars().contains(&'\n') {
21537                                    new_inlays.push(inlay);
21538                                }
21539                            });
21540                    }
21541
21542                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21543                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21544
21545                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21546                })
21547                .ok()?;
21548            Some(())
21549        });
21550    }
21551
21552    fn on_buffer_event(
21553        &mut self,
21554        multibuffer: &Entity<MultiBuffer>,
21555        event: &multi_buffer::Event,
21556        window: &mut Window,
21557        cx: &mut Context<Self>,
21558    ) {
21559        match event {
21560            multi_buffer::Event::Edited { edited_buffer } => {
21561                self.scrollbar_marker_state.dirty = true;
21562                self.active_indent_guides_state.dirty = true;
21563                self.refresh_active_diagnostics(cx);
21564                self.refresh_code_actions(window, cx);
21565                self.refresh_single_line_folds(window, cx);
21566                self.refresh_matching_bracket_highlights(window, cx);
21567                if self.has_active_edit_prediction() {
21568                    self.update_visible_edit_prediction(window, cx);
21569                }
21570
21571                if let Some(buffer) = edited_buffer {
21572                    if buffer.read(cx).file().is_none() {
21573                        cx.emit(EditorEvent::TitleChanged);
21574                    }
21575
21576                    if self.project.is_some() {
21577                        let buffer_id = buffer.read(cx).remote_id();
21578                        self.register_buffer(buffer_id, cx);
21579                        self.update_lsp_data(Some(buffer_id), window, cx);
21580                        self.refresh_inlay_hints(
21581                            InlayHintRefreshReason::BufferEdited(buffer_id),
21582                            cx,
21583                        );
21584                    }
21585                }
21586
21587                cx.emit(EditorEvent::BufferEdited);
21588                cx.emit(SearchEvent::MatchesInvalidated);
21589
21590                let Some(project) = &self.project else { return };
21591                let (telemetry, is_via_ssh) = {
21592                    let project = project.read(cx);
21593                    let telemetry = project.client().telemetry().clone();
21594                    let is_via_ssh = project.is_via_remote_server();
21595                    (telemetry, is_via_ssh)
21596                };
21597                telemetry.log_edit_event("editor", is_via_ssh);
21598            }
21599            multi_buffer::Event::ExcerptsAdded {
21600                buffer,
21601                predecessor,
21602                excerpts,
21603            } => {
21604                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21605                let buffer_id = buffer.read(cx).remote_id();
21606                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21607                    && let Some(project) = &self.project
21608                {
21609                    update_uncommitted_diff_for_buffer(
21610                        cx.entity(),
21611                        project,
21612                        [buffer.clone()],
21613                        self.buffer.clone(),
21614                        cx,
21615                    )
21616                    .detach();
21617                }
21618                self.update_lsp_data(Some(buffer_id), window, cx);
21619                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21620                self.colorize_brackets(false, cx);
21621                cx.emit(EditorEvent::ExcerptsAdded {
21622                    buffer: buffer.clone(),
21623                    predecessor: *predecessor,
21624                    excerpts: excerpts.clone(),
21625                });
21626            }
21627            multi_buffer::Event::ExcerptsRemoved {
21628                ids,
21629                removed_buffer_ids,
21630            } => {
21631                if let Some(inlay_hints) = &mut self.inlay_hints {
21632                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21633                }
21634                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21635                for buffer_id in removed_buffer_ids {
21636                    self.registered_buffers.remove(buffer_id);
21637                }
21638                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21639                cx.emit(EditorEvent::ExcerptsRemoved {
21640                    ids: ids.clone(),
21641                    removed_buffer_ids: removed_buffer_ids.clone(),
21642                });
21643            }
21644            multi_buffer::Event::ExcerptsEdited {
21645                excerpt_ids,
21646                buffer_ids,
21647            } => {
21648                self.display_map.update(cx, |map, cx| {
21649                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21650                });
21651                cx.emit(EditorEvent::ExcerptsEdited {
21652                    ids: excerpt_ids.clone(),
21653                });
21654            }
21655            multi_buffer::Event::ExcerptsExpanded { ids } => {
21656                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21657                self.refresh_document_highlights(cx);
21658                for id in ids {
21659                    self.fetched_tree_sitter_chunks.remove(id);
21660                }
21661                self.colorize_brackets(false, cx);
21662                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21663            }
21664            multi_buffer::Event::Reparsed(buffer_id) => {
21665                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21666                self.refresh_selected_text_highlights(true, window, cx);
21667                self.colorize_brackets(true, cx);
21668                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21669
21670                cx.emit(EditorEvent::Reparsed(*buffer_id));
21671            }
21672            multi_buffer::Event::DiffHunksToggled => {
21673                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21674            }
21675            multi_buffer::Event::LanguageChanged(buffer_id) => {
21676                self.registered_buffers.remove(&buffer_id);
21677                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21678                cx.emit(EditorEvent::Reparsed(*buffer_id));
21679                cx.notify();
21680            }
21681            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21682            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21683            multi_buffer::Event::FileHandleChanged
21684            | multi_buffer::Event::Reloaded
21685            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21686            multi_buffer::Event::DiagnosticsUpdated => {
21687                self.update_diagnostics_state(window, cx);
21688            }
21689            _ => {}
21690        };
21691    }
21692
21693    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21694        if !self.diagnostics_enabled() {
21695            return;
21696        }
21697        self.refresh_active_diagnostics(cx);
21698        self.refresh_inline_diagnostics(true, window, cx);
21699        self.scrollbar_marker_state.dirty = true;
21700        cx.notify();
21701    }
21702
21703    pub fn start_temporary_diff_override(&mut self) {
21704        self.load_diff_task.take();
21705        self.temporary_diff_override = true;
21706    }
21707
21708    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21709        self.temporary_diff_override = false;
21710        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21711        self.buffer.update(cx, |buffer, cx| {
21712            buffer.set_all_diff_hunks_collapsed(cx);
21713        });
21714
21715        if let Some(project) = self.project.clone() {
21716            self.load_diff_task = Some(
21717                update_uncommitted_diff_for_buffer(
21718                    cx.entity(),
21719                    &project,
21720                    self.buffer.read(cx).all_buffers(),
21721                    self.buffer.clone(),
21722                    cx,
21723                )
21724                .shared(),
21725            );
21726        }
21727    }
21728
21729    fn on_display_map_changed(
21730        &mut self,
21731        _: Entity<DisplayMap>,
21732        _: &mut Window,
21733        cx: &mut Context<Self>,
21734    ) {
21735        cx.notify();
21736    }
21737
21738    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
21739        if !self.mode.is_full() {
21740            return None;
21741        }
21742
21743        let theme_settings = theme::ThemeSettings::get_global(cx);
21744        let theme = cx.theme();
21745        let accent_colors = theme.accents().clone();
21746
21747        let accent_overrides = theme_settings
21748            .theme_overrides
21749            .get(theme.name.as_ref())
21750            .map(|theme_style| &theme_style.accents)
21751            .into_iter()
21752            .flatten()
21753            .chain(
21754                theme_settings
21755                    .experimental_theme_overrides
21756                    .as_ref()
21757                    .map(|overrides| &overrides.accents)
21758                    .into_iter()
21759                    .flatten(),
21760            )
21761            .flat_map(|accent| accent.0.clone())
21762            .collect();
21763
21764        Some(AccentData {
21765            colors: accent_colors,
21766            overrides: accent_overrides,
21767        })
21768    }
21769
21770    fn fetch_applicable_language_settings(
21771        &self,
21772        cx: &App,
21773    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
21774        if !self.mode.is_full() {
21775            return HashMap::default();
21776        }
21777
21778        self.buffer().read(cx).all_buffers().into_iter().fold(
21779            HashMap::default(),
21780            |mut acc, buffer| {
21781                let buffer = buffer.read(cx);
21782                let language = buffer.language().map(|language| language.name());
21783                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
21784                    let file = buffer.file();
21785                    v.insert(language_settings(language, file, cx).into_owned());
21786                }
21787                acc
21788            },
21789        )
21790    }
21791
21792    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21793        let new_language_settings = self.fetch_applicable_language_settings(cx);
21794        let language_settings_changed = new_language_settings != self.applicable_language_settings;
21795        self.applicable_language_settings = new_language_settings;
21796
21797        let new_accents = self.fetch_accent_data(cx);
21798        let accents_changed = new_accents != self.accent_data;
21799        self.accent_data = new_accents;
21800
21801        if self.diagnostics_enabled() {
21802            let new_severity = EditorSettings::get_global(cx)
21803                .diagnostics_max_severity
21804                .unwrap_or(DiagnosticSeverity::Hint);
21805            self.set_max_diagnostics_severity(new_severity, cx);
21806        }
21807        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21808        self.update_edit_prediction_settings(cx);
21809        self.refresh_edit_prediction(true, false, window, cx);
21810        self.refresh_inline_values(cx);
21811        self.refresh_inlay_hints(
21812            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21813                self.selections.newest_anchor().head(),
21814                &self.buffer.read(cx).snapshot(cx),
21815                cx,
21816            )),
21817            cx,
21818        );
21819
21820        let old_cursor_shape = self.cursor_shape;
21821        let old_show_breadcrumbs = self.show_breadcrumbs;
21822
21823        {
21824            let editor_settings = EditorSettings::get_global(cx);
21825            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21826            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21827            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21828            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21829        }
21830
21831        if old_cursor_shape != self.cursor_shape {
21832            cx.emit(EditorEvent::CursorShapeChanged);
21833        }
21834
21835        if old_show_breadcrumbs != self.show_breadcrumbs {
21836            cx.emit(EditorEvent::BreadcrumbsChanged);
21837        }
21838
21839        let project_settings = ProjectSettings::get_global(cx);
21840        self.buffer_serialization = self
21841            .should_serialize_buffer()
21842            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21843
21844        if self.mode.is_full() {
21845            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21846            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21847            if self.show_inline_diagnostics != show_inline_diagnostics {
21848                self.show_inline_diagnostics = show_inline_diagnostics;
21849                self.refresh_inline_diagnostics(false, window, cx);
21850            }
21851
21852            if self.git_blame_inline_enabled != inline_blame_enabled {
21853                self.toggle_git_blame_inline_internal(false, window, cx);
21854            }
21855
21856            let minimap_settings = EditorSettings::get_global(cx).minimap;
21857            if self.minimap_visibility != MinimapVisibility::Disabled {
21858                if self.minimap_visibility.settings_visibility()
21859                    != minimap_settings.minimap_enabled()
21860                {
21861                    self.set_minimap_visibility(
21862                        MinimapVisibility::for_mode(self.mode(), cx),
21863                        window,
21864                        cx,
21865                    );
21866                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21867                    minimap_entity.update(cx, |minimap_editor, cx| {
21868                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21869                    })
21870                }
21871            }
21872
21873            if language_settings_changed || accents_changed {
21874                self.colorize_brackets(true, cx);
21875            }
21876
21877            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21878                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21879            }) {
21880                if !inlay_splice.is_empty() {
21881                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21882                }
21883                self.refresh_colors_for_visible_range(None, window, cx);
21884            }
21885        }
21886
21887        cx.notify();
21888    }
21889
21890    pub fn set_searchable(&mut self, searchable: bool) {
21891        self.searchable = searchable;
21892    }
21893
21894    pub fn searchable(&self) -> bool {
21895        self.searchable
21896    }
21897
21898    pub fn open_excerpts_in_split(
21899        &mut self,
21900        _: &OpenExcerptsSplit,
21901        window: &mut Window,
21902        cx: &mut Context<Self>,
21903    ) {
21904        self.open_excerpts_common(None, true, window, cx)
21905    }
21906
21907    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21908        self.open_excerpts_common(None, false, window, cx)
21909    }
21910
21911    fn open_excerpts_common(
21912        &mut self,
21913        jump_data: Option<JumpData>,
21914        split: bool,
21915        window: &mut Window,
21916        cx: &mut Context<Self>,
21917    ) {
21918        let Some(workspace) = self.workspace() else {
21919            cx.propagate();
21920            return;
21921        };
21922
21923        if self.buffer.read(cx).is_singleton() {
21924            cx.propagate();
21925            return;
21926        }
21927
21928        let mut new_selections_by_buffer = HashMap::default();
21929        match &jump_data {
21930            Some(JumpData::MultiBufferPoint {
21931                excerpt_id,
21932                position,
21933                anchor,
21934                line_offset_from_top,
21935            }) => {
21936                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21937                if let Some(buffer) = multi_buffer_snapshot
21938                    .buffer_id_for_excerpt(*excerpt_id)
21939                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21940                {
21941                    let buffer_snapshot = buffer.read(cx).snapshot();
21942                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21943                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21944                    } else {
21945                        buffer_snapshot.clip_point(*position, Bias::Left)
21946                    };
21947                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21948                    new_selections_by_buffer.insert(
21949                        buffer,
21950                        (
21951                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
21952                            Some(*line_offset_from_top),
21953                        ),
21954                    );
21955                }
21956            }
21957            Some(JumpData::MultiBufferRow {
21958                row,
21959                line_offset_from_top,
21960            }) => {
21961                let point = MultiBufferPoint::new(row.0, 0);
21962                if let Some((buffer, buffer_point, _)) =
21963                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21964                {
21965                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21966                    new_selections_by_buffer
21967                        .entry(buffer)
21968                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21969                        .0
21970                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
21971                }
21972            }
21973            None => {
21974                let selections = self
21975                    .selections
21976                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
21977                let multi_buffer = self.buffer.read(cx);
21978                for selection in selections {
21979                    for (snapshot, range, _, anchor) in multi_buffer
21980                        .snapshot(cx)
21981                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21982                    {
21983                        if let Some(anchor) = anchor {
21984                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21985                            else {
21986                                continue;
21987                            };
21988                            let offset = text::ToOffset::to_offset(
21989                                &anchor.text_anchor,
21990                                &buffer_handle.read(cx).snapshot(),
21991                            );
21992                            let range = BufferOffset(offset)..BufferOffset(offset);
21993                            new_selections_by_buffer
21994                                .entry(buffer_handle)
21995                                .or_insert((Vec::new(), None))
21996                                .0
21997                                .push(range)
21998                        } else {
21999                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22000                            else {
22001                                continue;
22002                            };
22003                            new_selections_by_buffer
22004                                .entry(buffer_handle)
22005                                .or_insert((Vec::new(), None))
22006                                .0
22007                                .push(range)
22008                        }
22009                    }
22010                }
22011            }
22012        }
22013
22014        new_selections_by_buffer
22015            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22016
22017        if new_selections_by_buffer.is_empty() {
22018            return;
22019        }
22020
22021        // We defer the pane interaction because we ourselves are a workspace item
22022        // and activating a new item causes the pane to call a method on us reentrantly,
22023        // which panics if we're on the stack.
22024        window.defer(cx, move |window, cx| {
22025            workspace.update(cx, |workspace, cx| {
22026                let pane = if split {
22027                    workspace.adjacent_pane(window, cx)
22028                } else {
22029                    workspace.active_pane().clone()
22030                };
22031
22032                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22033                    let buffer_read = buffer.read(cx);
22034                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22035                        (true, project::File::from_dyn(Some(file)).is_some())
22036                    } else {
22037                        (false, false)
22038                    };
22039
22040                    // If project file is none workspace.open_project_item will fail to open the excerpt
22041                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22042                    // so we check if there's a tab match in that case first
22043                    let editor = (!has_file || !is_project_file)
22044                        .then(|| {
22045                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22046                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22047                            // Instead, we try to activate the existing editor in the pane first.
22048                            let (editor, pane_item_index, pane_item_id) =
22049                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22050                                    let editor = item.downcast::<Editor>()?;
22051                                    let singleton_buffer =
22052                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22053                                    if singleton_buffer == buffer {
22054                                        Some((editor, i, item.item_id()))
22055                                    } else {
22056                                        None
22057                                    }
22058                                })?;
22059                            pane.update(cx, |pane, cx| {
22060                                pane.activate_item(pane_item_index, true, true, window, cx);
22061                                if !PreviewTabsSettings::get_global(cx)
22062                                    .enable_preview_from_multibuffer
22063                                {
22064                                    pane.unpreview_item_if_preview(pane_item_id);
22065                                }
22066                            });
22067                            Some(editor)
22068                        })
22069                        .flatten()
22070                        .unwrap_or_else(|| {
22071                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22072                                .enable_keep_preview_on_code_navigation;
22073                            let allow_new_preview =
22074                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22075                            workspace.open_project_item::<Self>(
22076                                pane.clone(),
22077                                buffer,
22078                                true,
22079                                true,
22080                                keep_old_preview,
22081                                allow_new_preview,
22082                                window,
22083                                cx,
22084                            )
22085                        });
22086
22087                    editor.update(cx, |editor, cx| {
22088                        if has_file && !is_project_file {
22089                            editor.set_read_only(true);
22090                        }
22091                        let autoscroll = match scroll_offset {
22092                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22093                            None => Autoscroll::newest(),
22094                        };
22095                        let nav_history = editor.nav_history.take();
22096                        editor.change_selections(
22097                            SelectionEffects::scroll(autoscroll),
22098                            window,
22099                            cx,
22100                            |s| {
22101                                s.select_ranges(ranges.into_iter().map(|range| {
22102                                    // we checked that the editor is a singleton editor so the offsets are valid
22103                                    MultiBufferOffset(range.start.0)..MultiBufferOffset(range.end.0)
22104                                }));
22105                            },
22106                        );
22107                        editor.nav_history = nav_history;
22108                    });
22109                }
22110            })
22111        });
22112    }
22113
22114    // Allow opening excerpts for buffers that either belong to the current project
22115    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22116    // are also supported so tests and other in-memory views keep working.
22117    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22118        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22119    }
22120
22121    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22122        let snapshot = self.buffer.read(cx).read(cx);
22123        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22124        Some(
22125            ranges
22126                .iter()
22127                .map(move |range| {
22128                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22129                })
22130                .collect(),
22131        )
22132    }
22133
22134    fn selection_replacement_ranges(
22135        &self,
22136        range: Range<MultiBufferOffsetUtf16>,
22137        cx: &mut App,
22138    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22139        let selections = self
22140            .selections
22141            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22142        let newest_selection = selections
22143            .iter()
22144            .max_by_key(|selection| selection.id)
22145            .unwrap();
22146        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22147        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22148        let snapshot = self.buffer.read(cx).read(cx);
22149        selections
22150            .into_iter()
22151            .map(|mut selection| {
22152                selection.start.0.0 =
22153                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22154                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22155                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22156                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22157            })
22158            .collect()
22159    }
22160
22161    fn report_editor_event(
22162        &self,
22163        reported_event: ReportEditorEvent,
22164        file_extension: Option<String>,
22165        cx: &App,
22166    ) {
22167        if cfg!(any(test, feature = "test-support")) {
22168            return;
22169        }
22170
22171        let Some(project) = &self.project else { return };
22172
22173        // If None, we are in a file without an extension
22174        let file = self
22175            .buffer
22176            .read(cx)
22177            .as_singleton()
22178            .and_then(|b| b.read(cx).file());
22179        let file_extension = file_extension.or(file
22180            .as_ref()
22181            .and_then(|file| Path::new(file.file_name(cx)).extension())
22182            .and_then(|e| e.to_str())
22183            .map(|a| a.to_string()));
22184
22185        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22186            .map(|vim_mode| vim_mode.0)
22187            .unwrap_or(false);
22188
22189        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22190        let copilot_enabled = edit_predictions_provider
22191            == language::language_settings::EditPredictionProvider::Copilot;
22192        let copilot_enabled_for_language = self
22193            .buffer
22194            .read(cx)
22195            .language_settings(cx)
22196            .show_edit_predictions;
22197
22198        let project = project.read(cx);
22199        let event_type = reported_event.event_type();
22200
22201        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22202            telemetry::event!(
22203                event_type,
22204                type = if auto_saved {"autosave"} else {"manual"},
22205                file_extension,
22206                vim_mode,
22207                copilot_enabled,
22208                copilot_enabled_for_language,
22209                edit_predictions_provider,
22210                is_via_ssh = project.is_via_remote_server(),
22211            );
22212        } else {
22213            telemetry::event!(
22214                event_type,
22215                file_extension,
22216                vim_mode,
22217                copilot_enabled,
22218                copilot_enabled_for_language,
22219                edit_predictions_provider,
22220                is_via_ssh = project.is_via_remote_server(),
22221            );
22222        };
22223    }
22224
22225    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22226    /// with each line being an array of {text, highlight} objects.
22227    fn copy_highlight_json(
22228        &mut self,
22229        _: &CopyHighlightJson,
22230        window: &mut Window,
22231        cx: &mut Context<Self>,
22232    ) {
22233        #[derive(Serialize)]
22234        struct Chunk<'a> {
22235            text: String,
22236            highlight: Option<&'a str>,
22237        }
22238
22239        let snapshot = self.buffer.read(cx).snapshot(cx);
22240        let range = self
22241            .selected_text_range(false, window, cx)
22242            .and_then(|selection| {
22243                if selection.range.is_empty() {
22244                    None
22245                } else {
22246                    Some(
22247                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22248                            selection.range.start,
22249                        )))
22250                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22251                                selection.range.end,
22252                            ))),
22253                    )
22254                }
22255            })
22256            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22257
22258        let chunks = snapshot.chunks(range, true);
22259        let mut lines = Vec::new();
22260        let mut line: VecDeque<Chunk> = VecDeque::new();
22261
22262        let Some(style) = self.style.as_ref() else {
22263            return;
22264        };
22265
22266        for chunk in chunks {
22267            let highlight = chunk
22268                .syntax_highlight_id
22269                .and_then(|id| id.name(&style.syntax));
22270            let mut chunk_lines = chunk.text.split('\n').peekable();
22271            while let Some(text) = chunk_lines.next() {
22272                let mut merged_with_last_token = false;
22273                if let Some(last_token) = line.back_mut()
22274                    && last_token.highlight == highlight
22275                {
22276                    last_token.text.push_str(text);
22277                    merged_with_last_token = true;
22278                }
22279
22280                if !merged_with_last_token {
22281                    line.push_back(Chunk {
22282                        text: text.into(),
22283                        highlight,
22284                    });
22285                }
22286
22287                if chunk_lines.peek().is_some() {
22288                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22289                        line.pop_front();
22290                    }
22291                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22292                        line.pop_back();
22293                    }
22294
22295                    lines.push(mem::take(&mut line));
22296                }
22297            }
22298        }
22299
22300        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22301            return;
22302        };
22303        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22304    }
22305
22306    pub fn open_context_menu(
22307        &mut self,
22308        _: &OpenContextMenu,
22309        window: &mut Window,
22310        cx: &mut Context<Self>,
22311    ) {
22312        self.request_autoscroll(Autoscroll::newest(), cx);
22313        let position = self
22314            .selections
22315            .newest_display(&self.display_snapshot(cx))
22316            .start;
22317        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22318    }
22319
22320    pub fn replay_insert_event(
22321        &mut self,
22322        text: &str,
22323        relative_utf16_range: Option<Range<isize>>,
22324        window: &mut Window,
22325        cx: &mut Context<Self>,
22326    ) {
22327        if !self.input_enabled {
22328            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22329            return;
22330        }
22331        if let Some(relative_utf16_range) = relative_utf16_range {
22332            let selections = self
22333                .selections
22334                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22335            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22336                let new_ranges = selections.into_iter().map(|range| {
22337                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22338                        range
22339                            .head()
22340                            .0
22341                            .0
22342                            .saturating_add_signed(relative_utf16_range.start),
22343                    ));
22344                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22345                        range
22346                            .head()
22347                            .0
22348                            .0
22349                            .saturating_add_signed(relative_utf16_range.end),
22350                    ));
22351                    start..end
22352                });
22353                s.select_ranges(new_ranges);
22354            });
22355        }
22356
22357        self.handle_input(text, window, cx);
22358    }
22359
22360    pub fn is_focused(&self, window: &Window) -> bool {
22361        self.focus_handle.is_focused(window)
22362    }
22363
22364    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22365        cx.emit(EditorEvent::Focused);
22366
22367        if let Some(descendant) = self
22368            .last_focused_descendant
22369            .take()
22370            .and_then(|descendant| descendant.upgrade())
22371        {
22372            window.focus(&descendant);
22373        } else {
22374            if let Some(blame) = self.blame.as_ref() {
22375                blame.update(cx, GitBlame::focus)
22376            }
22377
22378            self.blink_manager.update(cx, BlinkManager::enable);
22379            self.show_cursor_names(window, cx);
22380            self.buffer.update(cx, |buffer, cx| {
22381                buffer.finalize_last_transaction(cx);
22382                if self.leader_id.is_none() {
22383                    buffer.set_active_selections(
22384                        &self.selections.disjoint_anchors_arc(),
22385                        self.selections.line_mode(),
22386                        self.cursor_shape,
22387                        cx,
22388                    );
22389                }
22390            });
22391
22392            if let Some(position_map) = self.last_position_map.clone() {
22393                EditorElement::mouse_moved(
22394                    self,
22395                    &MouseMoveEvent {
22396                        position: window.mouse_position(),
22397                        pressed_button: None,
22398                        modifiers: window.modifiers(),
22399                    },
22400                    &position_map,
22401                    window,
22402                    cx,
22403                );
22404            }
22405        }
22406    }
22407
22408    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22409        cx.emit(EditorEvent::FocusedIn)
22410    }
22411
22412    fn handle_focus_out(
22413        &mut self,
22414        event: FocusOutEvent,
22415        _window: &mut Window,
22416        cx: &mut Context<Self>,
22417    ) {
22418        if event.blurred != self.focus_handle {
22419            self.last_focused_descendant = Some(event.blurred);
22420        }
22421        self.selection_drag_state = SelectionDragState::None;
22422        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22423    }
22424
22425    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22426        self.blink_manager.update(cx, BlinkManager::disable);
22427        self.buffer
22428            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22429
22430        if let Some(blame) = self.blame.as_ref() {
22431            blame.update(cx, GitBlame::blur)
22432        }
22433        if !self.hover_state.focused(window, cx) {
22434            hide_hover(self, cx);
22435        }
22436        if !self
22437            .context_menu
22438            .borrow()
22439            .as_ref()
22440            .is_some_and(|context_menu| context_menu.focused(window, cx))
22441        {
22442            self.hide_context_menu(window, cx);
22443        }
22444        self.take_active_edit_prediction(cx);
22445        cx.emit(EditorEvent::Blurred);
22446        cx.notify();
22447    }
22448
22449    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22450        let mut pending: String = window
22451            .pending_input_keystrokes()
22452            .into_iter()
22453            .flatten()
22454            .filter_map(|keystroke| keystroke.key_char.clone())
22455            .collect();
22456
22457        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22458            pending = "".to_string();
22459        }
22460
22461        let existing_pending = self
22462            .text_highlights::<PendingInput>(cx)
22463            .map(|(_, ranges)| ranges.to_vec());
22464        if existing_pending.is_none() && pending.is_empty() {
22465            return;
22466        }
22467        let transaction =
22468            self.transact(window, cx, |this, window, cx| {
22469                let selections = this
22470                    .selections
22471                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22472                let edits = selections
22473                    .iter()
22474                    .map(|selection| (selection.end..selection.end, pending.clone()));
22475                this.edit(edits, cx);
22476                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22477                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22478                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22479                    }));
22480                });
22481                if let Some(existing_ranges) = existing_pending {
22482                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22483                    this.edit(edits, cx);
22484                }
22485            });
22486
22487        let snapshot = self.snapshot(window, cx);
22488        let ranges = self
22489            .selections
22490            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22491            .into_iter()
22492            .map(|selection| {
22493                snapshot.buffer_snapshot().anchor_after(selection.end)
22494                    ..snapshot
22495                        .buffer_snapshot()
22496                        .anchor_before(selection.end + pending.len())
22497            })
22498            .collect();
22499
22500        if pending.is_empty() {
22501            self.clear_highlights::<PendingInput>(cx);
22502        } else {
22503            self.highlight_text::<PendingInput>(
22504                ranges,
22505                HighlightStyle {
22506                    underline: Some(UnderlineStyle {
22507                        thickness: px(1.),
22508                        color: None,
22509                        wavy: false,
22510                    }),
22511                    ..Default::default()
22512                },
22513                cx,
22514            );
22515        }
22516
22517        self.ime_transaction = self.ime_transaction.or(transaction);
22518        if let Some(transaction) = self.ime_transaction {
22519            self.buffer.update(cx, |buffer, cx| {
22520                buffer.group_until_transaction(transaction, cx);
22521            });
22522        }
22523
22524        if self.text_highlights::<PendingInput>(cx).is_none() {
22525            self.ime_transaction.take();
22526        }
22527    }
22528
22529    pub fn register_action_renderer(
22530        &mut self,
22531        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22532    ) -> Subscription {
22533        let id = self.next_editor_action_id.post_inc();
22534        self.editor_actions
22535            .borrow_mut()
22536            .insert(id, Box::new(listener));
22537
22538        let editor_actions = self.editor_actions.clone();
22539        Subscription::new(move || {
22540            editor_actions.borrow_mut().remove(&id);
22541        })
22542    }
22543
22544    pub fn register_action<A: Action>(
22545        &mut self,
22546        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22547    ) -> Subscription {
22548        let id = self.next_editor_action_id.post_inc();
22549        let listener = Arc::new(listener);
22550        self.editor_actions.borrow_mut().insert(
22551            id,
22552            Box::new(move |_, window, _| {
22553                let listener = listener.clone();
22554                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22555                    let action = action.downcast_ref().unwrap();
22556                    if phase == DispatchPhase::Bubble {
22557                        listener(action, window, cx)
22558                    }
22559                })
22560            }),
22561        );
22562
22563        let editor_actions = self.editor_actions.clone();
22564        Subscription::new(move || {
22565            editor_actions.borrow_mut().remove(&id);
22566        })
22567    }
22568
22569    pub fn file_header_size(&self) -> u32 {
22570        FILE_HEADER_HEIGHT
22571    }
22572
22573    pub fn restore(
22574        &mut self,
22575        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22576        window: &mut Window,
22577        cx: &mut Context<Self>,
22578    ) {
22579        let workspace = self.workspace();
22580        let project = self.project();
22581        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22582            let mut tasks = Vec::new();
22583            for (buffer_id, changes) in revert_changes {
22584                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22585                    buffer.update(cx, |buffer, cx| {
22586                        buffer.edit(
22587                            changes
22588                                .into_iter()
22589                                .map(|(range, text)| (range, text.to_string())),
22590                            None,
22591                            cx,
22592                        );
22593                    });
22594
22595                    if let Some(project) =
22596                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22597                    {
22598                        project.update(cx, |project, cx| {
22599                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22600                        })
22601                    }
22602                }
22603            }
22604            tasks
22605        });
22606        cx.spawn_in(window, async move |_, cx| {
22607            for (buffer, task) in save_tasks {
22608                let result = task.await;
22609                if result.is_err() {
22610                    let Some(path) = buffer
22611                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22612                        .ok()
22613                    else {
22614                        continue;
22615                    };
22616                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22617                        let Some(task) = cx
22618                            .update_window_entity(workspace, |workspace, window, cx| {
22619                                workspace
22620                                    .open_path_preview(path, None, false, false, false, window, cx)
22621                            })
22622                            .ok()
22623                        else {
22624                            continue;
22625                        };
22626                        task.await.log_err();
22627                    }
22628                }
22629            }
22630        })
22631        .detach();
22632        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22633            selections.refresh()
22634        });
22635    }
22636
22637    pub fn to_pixel_point(
22638        &self,
22639        source: multi_buffer::Anchor,
22640        editor_snapshot: &EditorSnapshot,
22641        window: &mut Window,
22642    ) -> Option<gpui::Point<Pixels>> {
22643        let source_point = source.to_display_point(editor_snapshot);
22644        self.display_to_pixel_point(source_point, editor_snapshot, window)
22645    }
22646
22647    pub fn display_to_pixel_point(
22648        &self,
22649        source: DisplayPoint,
22650        editor_snapshot: &EditorSnapshot,
22651        window: &mut Window,
22652    ) -> Option<gpui::Point<Pixels>> {
22653        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22654        let text_layout_details = self.text_layout_details(window);
22655        let scroll_top = text_layout_details
22656            .scroll_anchor
22657            .scroll_position(editor_snapshot)
22658            .y;
22659
22660        if source.row().as_f64() < scroll_top.floor() {
22661            return None;
22662        }
22663        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22664        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22665        Some(gpui::Point::new(source_x, source_y))
22666    }
22667
22668    pub fn has_visible_completions_menu(&self) -> bool {
22669        !self.edit_prediction_preview_is_active()
22670            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22671                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22672            })
22673    }
22674
22675    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22676        if self.mode.is_minimap() {
22677            return;
22678        }
22679        self.addons
22680            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22681    }
22682
22683    pub fn unregister_addon<T: Addon>(&mut self) {
22684        self.addons.remove(&std::any::TypeId::of::<T>());
22685    }
22686
22687    pub fn addon<T: Addon>(&self) -> Option<&T> {
22688        let type_id = std::any::TypeId::of::<T>();
22689        self.addons
22690            .get(&type_id)
22691            .and_then(|item| item.to_any().downcast_ref::<T>())
22692    }
22693
22694    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22695        let type_id = std::any::TypeId::of::<T>();
22696        self.addons
22697            .get_mut(&type_id)
22698            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22699    }
22700
22701    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22702        let text_layout_details = self.text_layout_details(window);
22703        let style = &text_layout_details.editor_style;
22704        let font_id = window.text_system().resolve_font(&style.text.font());
22705        let font_size = style.text.font_size.to_pixels(window.rem_size());
22706        let line_height = style.text.line_height_in_pixels(window.rem_size());
22707        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22708        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22709
22710        CharacterDimensions {
22711            em_width,
22712            em_advance,
22713            line_height,
22714        }
22715    }
22716
22717    pub fn last_gutter_dimensions(&self) -> &GutterDimensions {
22718        &self.gutter_dimensions
22719    }
22720
22721    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22722        self.load_diff_task.clone()
22723    }
22724
22725    fn read_metadata_from_db(
22726        &mut self,
22727        item_id: u64,
22728        workspace_id: WorkspaceId,
22729        window: &mut Window,
22730        cx: &mut Context<Editor>,
22731    ) {
22732        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22733            && !self.mode.is_minimap()
22734            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22735        {
22736            let buffer_snapshot = OnceCell::new();
22737
22738            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22739                && !folds.is_empty()
22740            {
22741                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22742                self.fold_ranges(
22743                    folds
22744                        .into_iter()
22745                        .map(|(start, end)| {
22746                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22747                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22748                        })
22749                        .collect(),
22750                    false,
22751                    window,
22752                    cx,
22753                );
22754            }
22755
22756            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22757                && !selections.is_empty()
22758            {
22759                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22760                // skip adding the initial selection to selection history
22761                self.selection_history.mode = SelectionHistoryMode::Skipping;
22762                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22763                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22764                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22765                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22766                    }));
22767                });
22768                self.selection_history.mode = SelectionHistoryMode::Normal;
22769            };
22770        }
22771
22772        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22773    }
22774
22775    fn update_lsp_data(
22776        &mut self,
22777        for_buffer: Option<BufferId>,
22778        window: &mut Window,
22779        cx: &mut Context<'_, Self>,
22780    ) {
22781        self.pull_diagnostics(for_buffer, window, cx);
22782        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22783    }
22784
22785    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22786        if self.ignore_lsp_data() {
22787            return;
22788        }
22789        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
22790            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22791        }
22792    }
22793
22794    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22795        if self.ignore_lsp_data() {
22796            return;
22797        }
22798
22799        if !self.registered_buffers.contains_key(&buffer_id)
22800            && let Some(project) = self.project.as_ref()
22801        {
22802            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22803                project.update(cx, |project, cx| {
22804                    self.registered_buffers.insert(
22805                        buffer_id,
22806                        project.register_buffer_with_language_servers(&buffer, cx),
22807                    );
22808                });
22809            } else {
22810                self.registered_buffers.remove(&buffer_id);
22811            }
22812        }
22813    }
22814
22815    fn ignore_lsp_data(&self) -> bool {
22816        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22817        // skip any LSP updates for it.
22818        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22819    }
22820}
22821
22822fn edit_for_markdown_paste<'a>(
22823    buffer: &MultiBufferSnapshot,
22824    range: Range<MultiBufferOffset>,
22825    to_insert: &'a str,
22826    url: Option<url::Url>,
22827) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
22828    if url.is_none() {
22829        return (range, Cow::Borrowed(to_insert));
22830    };
22831
22832    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22833
22834    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22835        Cow::Borrowed(to_insert)
22836    } else {
22837        Cow::Owned(format!("[{old_text}]({to_insert})"))
22838    };
22839    (range, new_text)
22840}
22841
22842fn process_completion_for_edit(
22843    completion: &Completion,
22844    intent: CompletionIntent,
22845    buffer: &Entity<Buffer>,
22846    cursor_position: &text::Anchor,
22847    cx: &mut Context<Editor>,
22848) -> CompletionEdit {
22849    let buffer = buffer.read(cx);
22850    let buffer_snapshot = buffer.snapshot();
22851    let (snippet, new_text) = if completion.is_snippet() {
22852        let mut snippet_source = completion.new_text.clone();
22853        // Workaround for typescript language server issues so that methods don't expand within
22854        // strings and functions with type expressions. The previous point is used because the query
22855        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22856        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22857        let previous_point = if previous_point.column > 0 {
22858            cursor_position.to_previous_offset(&buffer_snapshot)
22859        } else {
22860            cursor_position.to_offset(&buffer_snapshot)
22861        };
22862        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22863            && scope.prefers_label_for_snippet_in_completion()
22864            && let Some(label) = completion.label()
22865            && matches!(
22866                completion.kind(),
22867                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22868            )
22869        {
22870            snippet_source = label;
22871        }
22872        match Snippet::parse(&snippet_source).log_err() {
22873            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22874            None => (None, completion.new_text.clone()),
22875        }
22876    } else {
22877        (None, completion.new_text.clone())
22878    };
22879
22880    let mut range_to_replace = {
22881        let replace_range = &completion.replace_range;
22882        if let CompletionSource::Lsp {
22883            insert_range: Some(insert_range),
22884            ..
22885        } = &completion.source
22886        {
22887            debug_assert_eq!(
22888                insert_range.start, replace_range.start,
22889                "insert_range and replace_range should start at the same position"
22890            );
22891            debug_assert!(
22892                insert_range
22893                    .start
22894                    .cmp(cursor_position, &buffer_snapshot)
22895                    .is_le(),
22896                "insert_range should start before or at cursor position"
22897            );
22898            debug_assert!(
22899                replace_range
22900                    .start
22901                    .cmp(cursor_position, &buffer_snapshot)
22902                    .is_le(),
22903                "replace_range should start before or at cursor position"
22904            );
22905
22906            let should_replace = match intent {
22907                CompletionIntent::CompleteWithInsert => false,
22908                CompletionIntent::CompleteWithReplace => true,
22909                CompletionIntent::Complete | CompletionIntent::Compose => {
22910                    let insert_mode =
22911                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22912                            .completions
22913                            .lsp_insert_mode;
22914                    match insert_mode {
22915                        LspInsertMode::Insert => false,
22916                        LspInsertMode::Replace => true,
22917                        LspInsertMode::ReplaceSubsequence => {
22918                            let mut text_to_replace = buffer.chars_for_range(
22919                                buffer.anchor_before(replace_range.start)
22920                                    ..buffer.anchor_after(replace_range.end),
22921                            );
22922                            let mut current_needle = text_to_replace.next();
22923                            for haystack_ch in completion.label.text.chars() {
22924                                if let Some(needle_ch) = current_needle
22925                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22926                                {
22927                                    current_needle = text_to_replace.next();
22928                                }
22929                            }
22930                            current_needle.is_none()
22931                        }
22932                        LspInsertMode::ReplaceSuffix => {
22933                            if replace_range
22934                                .end
22935                                .cmp(cursor_position, &buffer_snapshot)
22936                                .is_gt()
22937                            {
22938                                let range_after_cursor = *cursor_position..replace_range.end;
22939                                let text_after_cursor = buffer
22940                                    .text_for_range(
22941                                        buffer.anchor_before(range_after_cursor.start)
22942                                            ..buffer.anchor_after(range_after_cursor.end),
22943                                    )
22944                                    .collect::<String>()
22945                                    .to_ascii_lowercase();
22946                                completion
22947                                    .label
22948                                    .text
22949                                    .to_ascii_lowercase()
22950                                    .ends_with(&text_after_cursor)
22951                            } else {
22952                                true
22953                            }
22954                        }
22955                    }
22956                }
22957            };
22958
22959            if should_replace {
22960                replace_range.clone()
22961            } else {
22962                insert_range.clone()
22963            }
22964        } else {
22965            replace_range.clone()
22966        }
22967    };
22968
22969    if range_to_replace
22970        .end
22971        .cmp(cursor_position, &buffer_snapshot)
22972        .is_lt()
22973    {
22974        range_to_replace.end = *cursor_position;
22975    }
22976
22977    let replace_range = range_to_replace.to_offset(buffer);
22978    CompletionEdit {
22979        new_text,
22980        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
22981        snippet,
22982    }
22983}
22984
22985struct CompletionEdit {
22986    new_text: String,
22987    replace_range: Range<BufferOffset>,
22988    snippet: Option<Snippet>,
22989}
22990
22991fn insert_extra_newline_brackets(
22992    buffer: &MultiBufferSnapshot,
22993    range: Range<MultiBufferOffset>,
22994    language: &language::LanguageScope,
22995) -> bool {
22996    let leading_whitespace_len = buffer
22997        .reversed_chars_at(range.start)
22998        .take_while(|c| c.is_whitespace() && *c != '\n')
22999        .map(|c| c.len_utf8())
23000        .sum::<usize>();
23001    let trailing_whitespace_len = buffer
23002        .chars_at(range.end)
23003        .take_while(|c| c.is_whitespace() && *c != '\n')
23004        .map(|c| c.len_utf8())
23005        .sum::<usize>();
23006    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23007
23008    language.brackets().any(|(pair, enabled)| {
23009        let pair_start = pair.start.trim_end();
23010        let pair_end = pair.end.trim_start();
23011
23012        enabled
23013            && pair.newline
23014            && buffer.contains_str_at(range.end, pair_end)
23015            && buffer.contains_str_at(
23016                range.start.saturating_sub_usize(pair_start.len()),
23017                pair_start,
23018            )
23019    })
23020}
23021
23022fn insert_extra_newline_tree_sitter(
23023    buffer: &MultiBufferSnapshot,
23024    range: Range<MultiBufferOffset>,
23025) -> bool {
23026    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23027        [(buffer, range, _)] => (*buffer, range.clone()),
23028        _ => return false,
23029    };
23030    let pair = {
23031        let mut result: Option<BracketMatch<usize>> = None;
23032
23033        for pair in buffer
23034            .all_bracket_ranges(range.start.0..range.end.0)
23035            .filter(move |pair| {
23036                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23037            })
23038        {
23039            let len = pair.close_range.end - pair.open_range.start;
23040
23041            if let Some(existing) = &result {
23042                let existing_len = existing.close_range.end - existing.open_range.start;
23043                if len > existing_len {
23044                    continue;
23045                }
23046            }
23047
23048            result = Some(pair);
23049        }
23050
23051        result
23052    };
23053    let Some(pair) = pair else {
23054        return false;
23055    };
23056    pair.newline_only
23057        && buffer
23058            .chars_for_range(pair.open_range.end..range.start.0)
23059            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23060            .all(|c| c.is_whitespace() && c != '\n')
23061}
23062
23063fn update_uncommitted_diff_for_buffer(
23064    editor: Entity<Editor>,
23065    project: &Entity<Project>,
23066    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23067    buffer: Entity<MultiBuffer>,
23068    cx: &mut App,
23069) -> Task<()> {
23070    let mut tasks = Vec::new();
23071    project.update(cx, |project, cx| {
23072        for buffer in buffers {
23073            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23074                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23075            }
23076        }
23077    });
23078    cx.spawn(async move |cx| {
23079        let diffs = future::join_all(tasks).await;
23080        if editor
23081            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23082            .unwrap_or(false)
23083        {
23084            return;
23085        }
23086
23087        buffer
23088            .update(cx, |buffer, cx| {
23089                for diff in diffs.into_iter().flatten() {
23090                    buffer.add_diff(diff, cx);
23091                }
23092            })
23093            .ok();
23094    })
23095}
23096
23097fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23098    let tab_size = tab_size.get() as usize;
23099    let mut width = offset;
23100
23101    for ch in text.chars() {
23102        width += if ch == '\t' {
23103            tab_size - (width % tab_size)
23104        } else {
23105            1
23106        };
23107    }
23108
23109    width - offset
23110}
23111
23112#[cfg(test)]
23113mod tests {
23114    use super::*;
23115
23116    #[test]
23117    fn test_string_size_with_expanded_tabs() {
23118        let nz = |val| NonZeroU32::new(val).unwrap();
23119        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23120        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23121        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23122        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23123        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23124        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23125        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23126        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23127    }
23128}
23129
23130/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23131struct WordBreakingTokenizer<'a> {
23132    input: &'a str,
23133}
23134
23135impl<'a> WordBreakingTokenizer<'a> {
23136    fn new(input: &'a str) -> Self {
23137        Self { input }
23138    }
23139}
23140
23141fn is_char_ideographic(ch: char) -> bool {
23142    use unicode_script::Script::*;
23143    use unicode_script::UnicodeScript;
23144    matches!(ch.script(), Han | Tangut | Yi)
23145}
23146
23147fn is_grapheme_ideographic(text: &str) -> bool {
23148    text.chars().any(is_char_ideographic)
23149}
23150
23151fn is_grapheme_whitespace(text: &str) -> bool {
23152    text.chars().any(|x| x.is_whitespace())
23153}
23154
23155fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23156    text.chars()
23157        .next()
23158        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23159}
23160
23161#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23162enum WordBreakToken<'a> {
23163    Word { token: &'a str, grapheme_len: usize },
23164    InlineWhitespace { token: &'a str, grapheme_len: usize },
23165    Newline,
23166}
23167
23168impl<'a> Iterator for WordBreakingTokenizer<'a> {
23169    /// Yields a span, the count of graphemes in the token, and whether it was
23170    /// whitespace. Note that it also breaks at word boundaries.
23171    type Item = WordBreakToken<'a>;
23172
23173    fn next(&mut self) -> Option<Self::Item> {
23174        use unicode_segmentation::UnicodeSegmentation;
23175        if self.input.is_empty() {
23176            return None;
23177        }
23178
23179        let mut iter = self.input.graphemes(true).peekable();
23180        let mut offset = 0;
23181        let mut grapheme_len = 0;
23182        if let Some(first_grapheme) = iter.next() {
23183            let is_newline = first_grapheme == "\n";
23184            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23185            offset += first_grapheme.len();
23186            grapheme_len += 1;
23187            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23188                if let Some(grapheme) = iter.peek().copied()
23189                    && should_stay_with_preceding_ideograph(grapheme)
23190                {
23191                    offset += grapheme.len();
23192                    grapheme_len += 1;
23193                }
23194            } else {
23195                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23196                let mut next_word_bound = words.peek().copied();
23197                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23198                    next_word_bound = words.next();
23199                }
23200                while let Some(grapheme) = iter.peek().copied() {
23201                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23202                        break;
23203                    };
23204                    if is_grapheme_whitespace(grapheme) != is_whitespace
23205                        || (grapheme == "\n") != is_newline
23206                    {
23207                        break;
23208                    };
23209                    offset += grapheme.len();
23210                    grapheme_len += 1;
23211                    iter.next();
23212                }
23213            }
23214            let token = &self.input[..offset];
23215            self.input = &self.input[offset..];
23216            if token == "\n" {
23217                Some(WordBreakToken::Newline)
23218            } else if is_whitespace {
23219                Some(WordBreakToken::InlineWhitespace {
23220                    token,
23221                    grapheme_len,
23222                })
23223            } else {
23224                Some(WordBreakToken::Word {
23225                    token,
23226                    grapheme_len,
23227                })
23228            }
23229        } else {
23230            None
23231        }
23232    }
23233}
23234
23235#[test]
23236fn test_word_breaking_tokenizer() {
23237    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23238        ("", &[]),
23239        ("  ", &[whitespace("  ", 2)]),
23240        ("Ʒ", &[word("Ʒ", 1)]),
23241        ("Ǽ", &[word("Ǽ", 1)]),
23242        ("", &[word("", 1)]),
23243        ("⋑⋑", &[word("⋑⋑", 2)]),
23244        (
23245            "原理,进而",
23246            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23247        ),
23248        (
23249            "hello world",
23250            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23251        ),
23252        (
23253            "hello, world",
23254            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23255        ),
23256        (
23257            "  hello world",
23258            &[
23259                whitespace("  ", 2),
23260                word("hello", 5),
23261                whitespace(" ", 1),
23262                word("world", 5),
23263            ],
23264        ),
23265        (
23266            "这是什么 \n 钢笔",
23267            &[
23268                word("", 1),
23269                word("", 1),
23270                word("", 1),
23271                word("", 1),
23272                whitespace(" ", 1),
23273                newline(),
23274                whitespace(" ", 1),
23275                word("", 1),
23276                word("", 1),
23277            ],
23278        ),
23279        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23280    ];
23281
23282    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23283        WordBreakToken::Word {
23284            token,
23285            grapheme_len,
23286        }
23287    }
23288
23289    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23290        WordBreakToken::InlineWhitespace {
23291            token,
23292            grapheme_len,
23293        }
23294    }
23295
23296    fn newline() -> WordBreakToken<'static> {
23297        WordBreakToken::Newline
23298    }
23299
23300    for (input, result) in tests {
23301        assert_eq!(
23302            WordBreakingTokenizer::new(input)
23303                .collect::<Vec<_>>()
23304                .as_slice(),
23305            *result,
23306        );
23307    }
23308}
23309
23310fn wrap_with_prefix(
23311    first_line_prefix: String,
23312    subsequent_lines_prefix: String,
23313    unwrapped_text: String,
23314    wrap_column: usize,
23315    tab_size: NonZeroU32,
23316    preserve_existing_whitespace: bool,
23317) -> String {
23318    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23319    let subsequent_lines_prefix_len =
23320        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23321    let mut wrapped_text = String::new();
23322    let mut current_line = first_line_prefix;
23323    let mut is_first_line = true;
23324
23325    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23326    let mut current_line_len = first_line_prefix_len;
23327    let mut in_whitespace = false;
23328    for token in tokenizer {
23329        let have_preceding_whitespace = in_whitespace;
23330        match token {
23331            WordBreakToken::Word {
23332                token,
23333                grapheme_len,
23334            } => {
23335                in_whitespace = false;
23336                let current_prefix_len = if is_first_line {
23337                    first_line_prefix_len
23338                } else {
23339                    subsequent_lines_prefix_len
23340                };
23341                if current_line_len + grapheme_len > wrap_column
23342                    && current_line_len != current_prefix_len
23343                {
23344                    wrapped_text.push_str(current_line.trim_end());
23345                    wrapped_text.push('\n');
23346                    is_first_line = false;
23347                    current_line = subsequent_lines_prefix.clone();
23348                    current_line_len = subsequent_lines_prefix_len;
23349                }
23350                current_line.push_str(token);
23351                current_line_len += grapheme_len;
23352            }
23353            WordBreakToken::InlineWhitespace {
23354                mut token,
23355                mut grapheme_len,
23356            } => {
23357                in_whitespace = true;
23358                if have_preceding_whitespace && !preserve_existing_whitespace {
23359                    continue;
23360                }
23361                if !preserve_existing_whitespace {
23362                    // Keep a single whitespace grapheme as-is
23363                    if let Some(first) =
23364                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23365                    {
23366                        token = first;
23367                    } else {
23368                        token = " ";
23369                    }
23370                    grapheme_len = 1;
23371                }
23372                let current_prefix_len = if is_first_line {
23373                    first_line_prefix_len
23374                } else {
23375                    subsequent_lines_prefix_len
23376                };
23377                if current_line_len + grapheme_len > wrap_column {
23378                    wrapped_text.push_str(current_line.trim_end());
23379                    wrapped_text.push('\n');
23380                    is_first_line = false;
23381                    current_line = subsequent_lines_prefix.clone();
23382                    current_line_len = subsequent_lines_prefix_len;
23383                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23384                    current_line.push_str(token);
23385                    current_line_len += grapheme_len;
23386                }
23387            }
23388            WordBreakToken::Newline => {
23389                in_whitespace = true;
23390                let current_prefix_len = if is_first_line {
23391                    first_line_prefix_len
23392                } else {
23393                    subsequent_lines_prefix_len
23394                };
23395                if preserve_existing_whitespace {
23396                    wrapped_text.push_str(current_line.trim_end());
23397                    wrapped_text.push('\n');
23398                    is_first_line = false;
23399                    current_line = subsequent_lines_prefix.clone();
23400                    current_line_len = subsequent_lines_prefix_len;
23401                } else if have_preceding_whitespace {
23402                    continue;
23403                } else if current_line_len + 1 > wrap_column
23404                    && current_line_len != current_prefix_len
23405                {
23406                    wrapped_text.push_str(current_line.trim_end());
23407                    wrapped_text.push('\n');
23408                    is_first_line = false;
23409                    current_line = subsequent_lines_prefix.clone();
23410                    current_line_len = subsequent_lines_prefix_len;
23411                } else if current_line_len != current_prefix_len {
23412                    current_line.push(' ');
23413                    current_line_len += 1;
23414                }
23415            }
23416        }
23417    }
23418
23419    if !current_line.is_empty() {
23420        wrapped_text.push_str(&current_line);
23421    }
23422    wrapped_text
23423}
23424
23425#[test]
23426fn test_wrap_with_prefix() {
23427    assert_eq!(
23428        wrap_with_prefix(
23429            "# ".to_string(),
23430            "# ".to_string(),
23431            "abcdefg".to_string(),
23432            4,
23433            NonZeroU32::new(4).unwrap(),
23434            false,
23435        ),
23436        "# abcdefg"
23437    );
23438    assert_eq!(
23439        wrap_with_prefix(
23440            "".to_string(),
23441            "".to_string(),
23442            "\thello world".to_string(),
23443            8,
23444            NonZeroU32::new(4).unwrap(),
23445            false,
23446        ),
23447        "hello\nworld"
23448    );
23449    assert_eq!(
23450        wrap_with_prefix(
23451            "// ".to_string(),
23452            "// ".to_string(),
23453            "xx \nyy zz aa bb cc".to_string(),
23454            12,
23455            NonZeroU32::new(4).unwrap(),
23456            false,
23457        ),
23458        "// xx yy zz\n// aa bb cc"
23459    );
23460    assert_eq!(
23461        wrap_with_prefix(
23462            String::new(),
23463            String::new(),
23464            "这是什么 \n 钢笔".to_string(),
23465            3,
23466            NonZeroU32::new(4).unwrap(),
23467            false,
23468        ),
23469        "这是什\n么 钢\n"
23470    );
23471    assert_eq!(
23472        wrap_with_prefix(
23473            String::new(),
23474            String::new(),
23475            format!("foo{}bar", '\u{2009}'), // thin space
23476            80,
23477            NonZeroU32::new(4).unwrap(),
23478            false,
23479        ),
23480        format!("foo{}bar", '\u{2009}')
23481    );
23482}
23483
23484pub trait CollaborationHub {
23485    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23486    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23487    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23488}
23489
23490impl CollaborationHub for Entity<Project> {
23491    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23492        self.read(cx).collaborators()
23493    }
23494
23495    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23496        self.read(cx).user_store().read(cx).participant_indices()
23497    }
23498
23499    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23500        let this = self.read(cx);
23501        let user_ids = this.collaborators().values().map(|c| c.user_id);
23502        this.user_store().read(cx).participant_names(user_ids, cx)
23503    }
23504}
23505
23506pub trait SemanticsProvider {
23507    fn hover(
23508        &self,
23509        buffer: &Entity<Buffer>,
23510        position: text::Anchor,
23511        cx: &mut App,
23512    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23513
23514    fn inline_values(
23515        &self,
23516        buffer_handle: Entity<Buffer>,
23517        range: Range<text::Anchor>,
23518        cx: &mut App,
23519    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23520
23521    fn applicable_inlay_chunks(
23522        &self,
23523        buffer: &Entity<Buffer>,
23524        ranges: &[Range<text::Anchor>],
23525        cx: &mut App,
23526    ) -> Vec<Range<BufferRow>>;
23527
23528    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23529
23530    fn inlay_hints(
23531        &self,
23532        invalidate: InvalidationStrategy,
23533        buffer: Entity<Buffer>,
23534        ranges: Vec<Range<text::Anchor>>,
23535        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23536        cx: &mut App,
23537    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23538
23539    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23540
23541    fn document_highlights(
23542        &self,
23543        buffer: &Entity<Buffer>,
23544        position: text::Anchor,
23545        cx: &mut App,
23546    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23547
23548    fn definitions(
23549        &self,
23550        buffer: &Entity<Buffer>,
23551        position: text::Anchor,
23552        kind: GotoDefinitionKind,
23553        cx: &mut App,
23554    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23555
23556    fn range_for_rename(
23557        &self,
23558        buffer: &Entity<Buffer>,
23559        position: text::Anchor,
23560        cx: &mut App,
23561    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23562
23563    fn perform_rename(
23564        &self,
23565        buffer: &Entity<Buffer>,
23566        position: text::Anchor,
23567        new_name: String,
23568        cx: &mut App,
23569    ) -> Option<Task<Result<ProjectTransaction>>>;
23570}
23571
23572pub trait CompletionProvider {
23573    fn completions(
23574        &self,
23575        excerpt_id: ExcerptId,
23576        buffer: &Entity<Buffer>,
23577        buffer_position: text::Anchor,
23578        trigger: CompletionContext,
23579        window: &mut Window,
23580        cx: &mut Context<Editor>,
23581    ) -> Task<Result<Vec<CompletionResponse>>>;
23582
23583    fn resolve_completions(
23584        &self,
23585        _buffer: Entity<Buffer>,
23586        _completion_indices: Vec<usize>,
23587        _completions: Rc<RefCell<Box<[Completion]>>>,
23588        _cx: &mut Context<Editor>,
23589    ) -> Task<Result<bool>> {
23590        Task::ready(Ok(false))
23591    }
23592
23593    fn apply_additional_edits_for_completion(
23594        &self,
23595        _buffer: Entity<Buffer>,
23596        _completions: Rc<RefCell<Box<[Completion]>>>,
23597        _completion_index: usize,
23598        _push_to_history: bool,
23599        _cx: &mut Context<Editor>,
23600    ) -> Task<Result<Option<language::Transaction>>> {
23601        Task::ready(Ok(None))
23602    }
23603
23604    fn is_completion_trigger(
23605        &self,
23606        buffer: &Entity<Buffer>,
23607        position: language::Anchor,
23608        text: &str,
23609        trigger_in_words: bool,
23610        cx: &mut Context<Editor>,
23611    ) -> bool;
23612
23613    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23614
23615    fn sort_completions(&self) -> bool {
23616        true
23617    }
23618
23619    fn filter_completions(&self) -> bool {
23620        true
23621    }
23622
23623    fn show_snippets(&self) -> bool {
23624        false
23625    }
23626}
23627
23628pub trait CodeActionProvider {
23629    fn id(&self) -> Arc<str>;
23630
23631    fn code_actions(
23632        &self,
23633        buffer: &Entity<Buffer>,
23634        range: Range<text::Anchor>,
23635        window: &mut Window,
23636        cx: &mut App,
23637    ) -> Task<Result<Vec<CodeAction>>>;
23638
23639    fn apply_code_action(
23640        &self,
23641        buffer_handle: Entity<Buffer>,
23642        action: CodeAction,
23643        excerpt_id: ExcerptId,
23644        push_to_history: bool,
23645        window: &mut Window,
23646        cx: &mut App,
23647    ) -> Task<Result<ProjectTransaction>>;
23648}
23649
23650impl CodeActionProvider for Entity<Project> {
23651    fn id(&self) -> Arc<str> {
23652        "project".into()
23653    }
23654
23655    fn code_actions(
23656        &self,
23657        buffer: &Entity<Buffer>,
23658        range: Range<text::Anchor>,
23659        _window: &mut Window,
23660        cx: &mut App,
23661    ) -> Task<Result<Vec<CodeAction>>> {
23662        self.update(cx, |project, cx| {
23663            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23664            let code_actions = project.code_actions(buffer, range, None, cx);
23665            cx.background_spawn(async move {
23666                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23667                Ok(code_lens_actions
23668                    .context("code lens fetch")?
23669                    .into_iter()
23670                    .flatten()
23671                    .chain(
23672                        code_actions
23673                            .context("code action fetch")?
23674                            .into_iter()
23675                            .flatten(),
23676                    )
23677                    .collect())
23678            })
23679        })
23680    }
23681
23682    fn apply_code_action(
23683        &self,
23684        buffer_handle: Entity<Buffer>,
23685        action: CodeAction,
23686        _excerpt_id: ExcerptId,
23687        push_to_history: bool,
23688        _window: &mut Window,
23689        cx: &mut App,
23690    ) -> Task<Result<ProjectTransaction>> {
23691        self.update(cx, |project, cx| {
23692            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23693        })
23694    }
23695}
23696
23697fn snippet_completions(
23698    project: &Project,
23699    buffer: &Entity<Buffer>,
23700    buffer_anchor: text::Anchor,
23701    classifier: CharClassifier,
23702    cx: &mut App,
23703) -> Task<Result<CompletionResponse>> {
23704    let languages = buffer.read(cx).languages_at(buffer_anchor);
23705    let snippet_store = project.snippets().read(cx);
23706
23707    let scopes: Vec<_> = languages
23708        .iter()
23709        .filter_map(|language| {
23710            let language_name = language.lsp_id();
23711            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23712
23713            if snippets.is_empty() {
23714                None
23715            } else {
23716                Some((language.default_scope(), snippets))
23717            }
23718        })
23719        .collect();
23720
23721    if scopes.is_empty() {
23722        return Task::ready(Ok(CompletionResponse {
23723            completions: vec![],
23724            display_options: CompletionDisplayOptions::default(),
23725            is_incomplete: false,
23726        }));
23727    }
23728
23729    let snapshot = buffer.read(cx).text_snapshot();
23730    let executor = cx.background_executor().clone();
23731
23732    cx.background_spawn(async move {
23733        let is_word_char = |c| classifier.is_word(c);
23734
23735        let mut is_incomplete = false;
23736        let mut completions: Vec<Completion> = Vec::new();
23737
23738        const MAX_PREFIX_LEN: usize = 128;
23739        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23740        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23741        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23742
23743        let max_buffer_window: String = snapshot
23744            .text_for_range(window_start..buffer_offset)
23745            .collect();
23746
23747        if max_buffer_window.is_empty() {
23748            return Ok(CompletionResponse {
23749                completions: vec![],
23750                display_options: CompletionDisplayOptions::default(),
23751                is_incomplete: true,
23752            });
23753        }
23754
23755        for (_scope, snippets) in scopes.into_iter() {
23756            // Sort snippets by word count to match longer snippet prefixes first.
23757            let mut sorted_snippet_candidates = snippets
23758                .iter()
23759                .enumerate()
23760                .flat_map(|(snippet_ix, snippet)| {
23761                    snippet
23762                        .prefix
23763                        .iter()
23764                        .enumerate()
23765                        .map(move |(prefix_ix, prefix)| {
23766                            let word_count =
23767                                snippet_candidate_suffixes(prefix, is_word_char).count();
23768                            ((snippet_ix, prefix_ix), prefix, word_count)
23769                        })
23770                })
23771                .collect_vec();
23772            sorted_snippet_candidates
23773                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23774
23775            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23776
23777            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23778                .take(
23779                    sorted_snippet_candidates
23780                        .first()
23781                        .map(|(_, _, word_count)| *word_count)
23782                        .unwrap_or_default(),
23783                )
23784                .collect_vec();
23785
23786            const MAX_RESULTS: usize = 100;
23787            // Each match also remembers how many characters from the buffer it consumed
23788            let mut matches: Vec<(StringMatch, usize)> = vec![];
23789
23790            let mut snippet_list_cutoff_index = 0;
23791            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23792                let word_count = buffer_index + 1;
23793                // Increase `snippet_list_cutoff_index` until we have all of the
23794                // snippets with sufficiently many words.
23795                while sorted_snippet_candidates
23796                    .get(snippet_list_cutoff_index)
23797                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23798                        *snippet_word_count >= word_count
23799                    })
23800                {
23801                    snippet_list_cutoff_index += 1;
23802                }
23803
23804                // Take only the candidates with at least `word_count` many words
23805                let snippet_candidates_at_word_len =
23806                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23807
23808                let candidates = snippet_candidates_at_word_len
23809                    .iter()
23810                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23811                    .enumerate() // index in `sorted_snippet_candidates`
23812                    // First char must match
23813                    .filter(|(_ix, prefix)| {
23814                        itertools::equal(
23815                            prefix
23816                                .chars()
23817                                .next()
23818                                .into_iter()
23819                                .flat_map(|c| c.to_lowercase()),
23820                            buffer_window
23821                                .chars()
23822                                .next()
23823                                .into_iter()
23824                                .flat_map(|c| c.to_lowercase()),
23825                        )
23826                    })
23827                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23828                    .collect::<Vec<StringMatchCandidate>>();
23829
23830                matches.extend(
23831                    fuzzy::match_strings(
23832                        &candidates,
23833                        &buffer_window,
23834                        buffer_window.chars().any(|c| c.is_uppercase()),
23835                        true,
23836                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23837                        &Default::default(),
23838                        executor.clone(),
23839                    )
23840                    .await
23841                    .into_iter()
23842                    .map(|string_match| (string_match, buffer_window.len())),
23843                );
23844
23845                if matches.len() >= MAX_RESULTS {
23846                    break;
23847                }
23848            }
23849
23850            let to_lsp = |point: &text::Anchor| {
23851                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23852                point_to_lsp(end)
23853            };
23854            let lsp_end = to_lsp(&buffer_anchor);
23855
23856            if matches.len() >= MAX_RESULTS {
23857                is_incomplete = true;
23858            }
23859
23860            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23861                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23862                    sorted_snippet_candidates[string_match.candidate_id];
23863                let snippet = &snippets[snippet_index];
23864                let start = buffer_offset - buffer_window_len;
23865                let start = snapshot.anchor_before(start);
23866                let range = start..buffer_anchor;
23867                let lsp_start = to_lsp(&start);
23868                let lsp_range = lsp::Range {
23869                    start: lsp_start,
23870                    end: lsp_end,
23871                };
23872                Completion {
23873                    replace_range: range,
23874                    new_text: snippet.body.clone(),
23875                    source: CompletionSource::Lsp {
23876                        insert_range: None,
23877                        server_id: LanguageServerId(usize::MAX),
23878                        resolved: true,
23879                        lsp_completion: Box::new(lsp::CompletionItem {
23880                            label: snippet.prefix.first().unwrap().clone(),
23881                            kind: Some(CompletionItemKind::SNIPPET),
23882                            label_details: snippet.description.as_ref().map(|description| {
23883                                lsp::CompletionItemLabelDetails {
23884                                    detail: Some(description.clone()),
23885                                    description: None,
23886                                }
23887                            }),
23888                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23889                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23890                                lsp::InsertReplaceEdit {
23891                                    new_text: snippet.body.clone(),
23892                                    insert: lsp_range,
23893                                    replace: lsp_range,
23894                                },
23895                            )),
23896                            filter_text: Some(snippet.body.clone()),
23897                            sort_text: Some(char::MAX.to_string()),
23898                            ..lsp::CompletionItem::default()
23899                        }),
23900                        lsp_defaults: None,
23901                    },
23902                    label: CodeLabel {
23903                        text: matching_prefix.clone(),
23904                        runs: Vec::new(),
23905                        filter_range: 0..matching_prefix.len(),
23906                    },
23907                    icon_path: None,
23908                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23909                        single_line: snippet.name.clone().into(),
23910                        plain_text: snippet
23911                            .description
23912                            .clone()
23913                            .map(|description| description.into()),
23914                    }),
23915                    insert_text_mode: None,
23916                    confirm: None,
23917                    match_start: Some(start),
23918                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23919                }
23920            }));
23921        }
23922
23923        Ok(CompletionResponse {
23924            completions,
23925            display_options: CompletionDisplayOptions::default(),
23926            is_incomplete,
23927        })
23928    })
23929}
23930
23931impl CompletionProvider for Entity<Project> {
23932    fn completions(
23933        &self,
23934        _excerpt_id: ExcerptId,
23935        buffer: &Entity<Buffer>,
23936        buffer_position: text::Anchor,
23937        options: CompletionContext,
23938        _window: &mut Window,
23939        cx: &mut Context<Editor>,
23940    ) -> Task<Result<Vec<CompletionResponse>>> {
23941        self.update(cx, |project, cx| {
23942            let task = project.completions(buffer, buffer_position, options, cx);
23943            cx.background_spawn(task)
23944        })
23945    }
23946
23947    fn resolve_completions(
23948        &self,
23949        buffer: Entity<Buffer>,
23950        completion_indices: Vec<usize>,
23951        completions: Rc<RefCell<Box<[Completion]>>>,
23952        cx: &mut Context<Editor>,
23953    ) -> Task<Result<bool>> {
23954        self.update(cx, |project, cx| {
23955            project.lsp_store().update(cx, |lsp_store, cx| {
23956                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23957            })
23958        })
23959    }
23960
23961    fn apply_additional_edits_for_completion(
23962        &self,
23963        buffer: Entity<Buffer>,
23964        completions: Rc<RefCell<Box<[Completion]>>>,
23965        completion_index: usize,
23966        push_to_history: bool,
23967        cx: &mut Context<Editor>,
23968    ) -> Task<Result<Option<language::Transaction>>> {
23969        self.update(cx, |project, cx| {
23970            project.lsp_store().update(cx, |lsp_store, cx| {
23971                lsp_store.apply_additional_edits_for_completion(
23972                    buffer,
23973                    completions,
23974                    completion_index,
23975                    push_to_history,
23976                    cx,
23977                )
23978            })
23979        })
23980    }
23981
23982    fn is_completion_trigger(
23983        &self,
23984        buffer: &Entity<Buffer>,
23985        position: language::Anchor,
23986        text: &str,
23987        trigger_in_words: bool,
23988        cx: &mut Context<Editor>,
23989    ) -> bool {
23990        let mut chars = text.chars();
23991        let char = if let Some(char) = chars.next() {
23992            char
23993        } else {
23994            return false;
23995        };
23996        if chars.next().is_some() {
23997            return false;
23998        }
23999
24000        let buffer = buffer.read(cx);
24001        let snapshot = buffer.snapshot();
24002        let classifier = snapshot
24003            .char_classifier_at(position)
24004            .scope_context(Some(CharScopeContext::Completion));
24005        if trigger_in_words && classifier.is_word(char) {
24006            return true;
24007        }
24008
24009        buffer.completion_triggers().contains(text)
24010    }
24011
24012    fn show_snippets(&self) -> bool {
24013        true
24014    }
24015}
24016
24017impl SemanticsProvider for Entity<Project> {
24018    fn hover(
24019        &self,
24020        buffer: &Entity<Buffer>,
24021        position: text::Anchor,
24022        cx: &mut App,
24023    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24024        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24025    }
24026
24027    fn document_highlights(
24028        &self,
24029        buffer: &Entity<Buffer>,
24030        position: text::Anchor,
24031        cx: &mut App,
24032    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24033        Some(self.update(cx, |project, cx| {
24034            project.document_highlights(buffer, position, cx)
24035        }))
24036    }
24037
24038    fn definitions(
24039        &self,
24040        buffer: &Entity<Buffer>,
24041        position: text::Anchor,
24042        kind: GotoDefinitionKind,
24043        cx: &mut App,
24044    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24045        Some(self.update(cx, |project, cx| match kind {
24046            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24047            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24048            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24049            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24050        }))
24051    }
24052
24053    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24054        self.update(cx, |project, cx| {
24055            if project
24056                .active_debug_session(cx)
24057                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24058            {
24059                return true;
24060            }
24061
24062            buffer.update(cx, |buffer, cx| {
24063                project.any_language_server_supports_inlay_hints(buffer, cx)
24064            })
24065        })
24066    }
24067
24068    fn inline_values(
24069        &self,
24070        buffer_handle: Entity<Buffer>,
24071        range: Range<text::Anchor>,
24072        cx: &mut App,
24073    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24074        self.update(cx, |project, cx| {
24075            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24076
24077            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24078        })
24079    }
24080
24081    fn applicable_inlay_chunks(
24082        &self,
24083        buffer: &Entity<Buffer>,
24084        ranges: &[Range<text::Anchor>],
24085        cx: &mut App,
24086    ) -> Vec<Range<BufferRow>> {
24087        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24088            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24089        })
24090    }
24091
24092    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24093        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24094            lsp_store.invalidate_inlay_hints(for_buffers)
24095        });
24096    }
24097
24098    fn inlay_hints(
24099        &self,
24100        invalidate: InvalidationStrategy,
24101        buffer: Entity<Buffer>,
24102        ranges: Vec<Range<text::Anchor>>,
24103        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24104        cx: &mut App,
24105    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24106        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24107            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24108        }))
24109    }
24110
24111    fn range_for_rename(
24112        &self,
24113        buffer: &Entity<Buffer>,
24114        position: text::Anchor,
24115        cx: &mut App,
24116    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24117        Some(self.update(cx, |project, cx| {
24118            let buffer = buffer.clone();
24119            let task = project.prepare_rename(buffer.clone(), position, cx);
24120            cx.spawn(async move |_, cx| {
24121                Ok(match task.await? {
24122                    PrepareRenameResponse::Success(range) => Some(range),
24123                    PrepareRenameResponse::InvalidPosition => None,
24124                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24125                        // Fallback on using TreeSitter info to determine identifier range
24126                        buffer.read_with(cx, |buffer, _| {
24127                            let snapshot = buffer.snapshot();
24128                            let (range, kind) = snapshot.surrounding_word(position, None);
24129                            if kind != Some(CharKind::Word) {
24130                                return None;
24131                            }
24132                            Some(
24133                                snapshot.anchor_before(range.start)
24134                                    ..snapshot.anchor_after(range.end),
24135                            )
24136                        })?
24137                    }
24138                })
24139            })
24140        }))
24141    }
24142
24143    fn perform_rename(
24144        &self,
24145        buffer: &Entity<Buffer>,
24146        position: text::Anchor,
24147        new_name: String,
24148        cx: &mut App,
24149    ) -> Option<Task<Result<ProjectTransaction>>> {
24150        Some(self.update(cx, |project, cx| {
24151            project.perform_rename(buffer.clone(), position, new_name, cx)
24152        }))
24153    }
24154}
24155
24156fn consume_contiguous_rows(
24157    contiguous_row_selections: &mut Vec<Selection<Point>>,
24158    selection: &Selection<Point>,
24159    display_map: &DisplaySnapshot,
24160    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24161) -> (MultiBufferRow, MultiBufferRow) {
24162    contiguous_row_selections.push(selection.clone());
24163    let start_row = starting_row(selection, display_map);
24164    let mut end_row = ending_row(selection, display_map);
24165
24166    while let Some(next_selection) = selections.peek() {
24167        if next_selection.start.row <= end_row.0 {
24168            end_row = ending_row(next_selection, display_map);
24169            contiguous_row_selections.push(selections.next().unwrap().clone());
24170        } else {
24171            break;
24172        }
24173    }
24174    (start_row, end_row)
24175}
24176
24177fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24178    if selection.start.column > 0 {
24179        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24180    } else {
24181        MultiBufferRow(selection.start.row)
24182    }
24183}
24184
24185fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24186    if next_selection.end.column > 0 || next_selection.is_empty() {
24187        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24188    } else {
24189        MultiBufferRow(next_selection.end.row)
24190    }
24191}
24192
24193impl EditorSnapshot {
24194    pub fn remote_selections_in_range<'a>(
24195        &'a self,
24196        range: &'a Range<Anchor>,
24197        collaboration_hub: &dyn CollaborationHub,
24198        cx: &'a App,
24199    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24200        let participant_names = collaboration_hub.user_names(cx);
24201        let participant_indices = collaboration_hub.user_participant_indices(cx);
24202        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24203        let collaborators_by_replica_id = collaborators_by_peer_id
24204            .values()
24205            .map(|collaborator| (collaborator.replica_id, collaborator))
24206            .collect::<HashMap<_, _>>();
24207        self.buffer_snapshot()
24208            .selections_in_range(range, false)
24209            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24210                if replica_id == ReplicaId::AGENT {
24211                    Some(RemoteSelection {
24212                        replica_id,
24213                        selection,
24214                        cursor_shape,
24215                        line_mode,
24216                        collaborator_id: CollaboratorId::Agent,
24217                        user_name: Some("Agent".into()),
24218                        color: cx.theme().players().agent(),
24219                    })
24220                } else {
24221                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24222                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24223                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24224                    Some(RemoteSelection {
24225                        replica_id,
24226                        selection,
24227                        cursor_shape,
24228                        line_mode,
24229                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24230                        user_name,
24231                        color: if let Some(index) = participant_index {
24232                            cx.theme().players().color_for_participant(index.0)
24233                        } else {
24234                            cx.theme().players().absent()
24235                        },
24236                    })
24237                }
24238            })
24239    }
24240
24241    pub fn hunks_for_ranges(
24242        &self,
24243        ranges: impl IntoIterator<Item = Range<Point>>,
24244    ) -> Vec<MultiBufferDiffHunk> {
24245        let mut hunks = Vec::new();
24246        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24247            HashMap::default();
24248        for query_range in ranges {
24249            let query_rows =
24250                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24251            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24252                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24253            ) {
24254                // Include deleted hunks that are adjacent to the query range, because
24255                // otherwise they would be missed.
24256                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24257                if hunk.status().is_deleted() {
24258                    intersects_range |= hunk.row_range.start == query_rows.end;
24259                    intersects_range |= hunk.row_range.end == query_rows.start;
24260                }
24261                if intersects_range {
24262                    if !processed_buffer_rows
24263                        .entry(hunk.buffer_id)
24264                        .or_default()
24265                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24266                    {
24267                        continue;
24268                    }
24269                    hunks.push(hunk);
24270                }
24271            }
24272        }
24273
24274        hunks
24275    }
24276
24277    fn display_diff_hunks_for_rows<'a>(
24278        &'a self,
24279        display_rows: Range<DisplayRow>,
24280        folded_buffers: &'a HashSet<BufferId>,
24281    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24282        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24283        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24284
24285        self.buffer_snapshot()
24286            .diff_hunks_in_range(buffer_start..buffer_end)
24287            .filter_map(|hunk| {
24288                if folded_buffers.contains(&hunk.buffer_id) {
24289                    return None;
24290                }
24291
24292                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24293                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24294
24295                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24296                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24297
24298                let display_hunk = if hunk_display_start.column() != 0 {
24299                    DisplayDiffHunk::Folded {
24300                        display_row: hunk_display_start.row(),
24301                    }
24302                } else {
24303                    let mut end_row = hunk_display_end.row();
24304                    if hunk_display_end.column() > 0 {
24305                        end_row.0 += 1;
24306                    }
24307                    let is_created_file = hunk.is_created_file();
24308
24309                    DisplayDiffHunk::Unfolded {
24310                        status: hunk.status(),
24311                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24312                            ..hunk.diff_base_byte_range.end.0,
24313                        word_diffs: hunk.word_diffs,
24314                        display_row_range: hunk_display_start.row()..end_row,
24315                        multi_buffer_range: Anchor::range_in_buffer(
24316                            hunk.excerpt_id,
24317                            hunk.buffer_range,
24318                        ),
24319                        is_created_file,
24320                    }
24321                };
24322
24323                Some(display_hunk)
24324            })
24325    }
24326
24327    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24328        self.display_snapshot
24329            .buffer_snapshot()
24330            .language_at(position)
24331    }
24332
24333    pub fn is_focused(&self) -> bool {
24334        self.is_focused
24335    }
24336
24337    pub fn placeholder_text(&self) -> Option<String> {
24338        self.placeholder_display_snapshot
24339            .as_ref()
24340            .map(|display_map| display_map.text())
24341    }
24342
24343    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24344        self.scroll_anchor.scroll_position(&self.display_snapshot)
24345    }
24346
24347    fn gutter_dimensions(
24348        &self,
24349        font_id: FontId,
24350        font_size: Pixels,
24351        max_line_number_width: Pixels,
24352        cx: &App,
24353    ) -> Option<GutterDimensions> {
24354        if !self.show_gutter {
24355            return None;
24356        }
24357
24358        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
24359        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
24360
24361        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24362            matches!(
24363                ProjectSettings::get_global(cx).git.git_gutter,
24364                GitGutterSetting::TrackedFiles
24365            )
24366        });
24367        let gutter_settings = EditorSettings::get_global(cx).gutter;
24368        let show_line_numbers = self
24369            .show_line_numbers
24370            .unwrap_or(gutter_settings.line_numbers);
24371        let line_gutter_width = if show_line_numbers {
24372            // Avoid flicker-like gutter resizes when the line number gains another digit by
24373            // only resizing the gutter on files with > 10**min_line_number_digits lines.
24374            let min_width_for_number_on_gutter =
24375                ch_advance * gutter_settings.min_line_number_digits as f32;
24376            max_line_number_width.max(min_width_for_number_on_gutter)
24377        } else {
24378            0.0.into()
24379        };
24380
24381        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24382        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24383
24384        let git_blame_entries_width =
24385            self.git_blame_gutter_max_author_length
24386                .map(|max_author_length| {
24387                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24388                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24389
24390                    /// The number of characters to dedicate to gaps and margins.
24391                    const SPACING_WIDTH: usize = 4;
24392
24393                    let max_char_count = max_author_length.min(renderer.max_author_length())
24394                        + ::git::SHORT_SHA_LENGTH
24395                        + MAX_RELATIVE_TIMESTAMP.len()
24396                        + SPACING_WIDTH;
24397
24398                    ch_advance * max_char_count
24399                });
24400
24401        let is_singleton = self.buffer_snapshot().is_singleton();
24402
24403        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24404        left_padding += if !is_singleton {
24405            ch_width * 4.0
24406        } else if show_runnables || show_breakpoints {
24407            ch_width * 3.0
24408        } else if show_git_gutter && show_line_numbers {
24409            ch_width * 2.0
24410        } else if show_git_gutter || show_line_numbers {
24411            ch_width
24412        } else {
24413            px(0.)
24414        };
24415
24416        let shows_folds = is_singleton && gutter_settings.folds;
24417
24418        let right_padding = if shows_folds && show_line_numbers {
24419            ch_width * 4.0
24420        } else if shows_folds || (!is_singleton && show_line_numbers) {
24421            ch_width * 3.0
24422        } else if show_line_numbers {
24423            ch_width
24424        } else {
24425            px(0.)
24426        };
24427
24428        Some(GutterDimensions {
24429            left_padding,
24430            right_padding,
24431            width: line_gutter_width + left_padding + right_padding,
24432            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24433            git_blame_entries_width,
24434        })
24435    }
24436
24437    pub fn render_crease_toggle(
24438        &self,
24439        buffer_row: MultiBufferRow,
24440        row_contains_cursor: bool,
24441        editor: Entity<Editor>,
24442        window: &mut Window,
24443        cx: &mut App,
24444    ) -> Option<AnyElement> {
24445        let folded = self.is_line_folded(buffer_row);
24446        let mut is_foldable = false;
24447
24448        if let Some(crease) = self
24449            .crease_snapshot
24450            .query_row(buffer_row, self.buffer_snapshot())
24451        {
24452            is_foldable = true;
24453            match crease {
24454                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24455                    if let Some(render_toggle) = render_toggle {
24456                        let toggle_callback =
24457                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24458                                if folded {
24459                                    editor.update(cx, |editor, cx| {
24460                                        editor.fold_at(buffer_row, window, cx)
24461                                    });
24462                                } else {
24463                                    editor.update(cx, |editor, cx| {
24464                                        editor.unfold_at(buffer_row, window, cx)
24465                                    });
24466                                }
24467                            });
24468                        return Some((render_toggle)(
24469                            buffer_row,
24470                            folded,
24471                            toggle_callback,
24472                            window,
24473                            cx,
24474                        ));
24475                    }
24476                }
24477            }
24478        }
24479
24480        is_foldable |= self.starts_indent(buffer_row);
24481
24482        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24483            Some(
24484                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24485                    .toggle_state(folded)
24486                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24487                        if folded {
24488                            this.unfold_at(buffer_row, window, cx);
24489                        } else {
24490                            this.fold_at(buffer_row, window, cx);
24491                        }
24492                    }))
24493                    .into_any_element(),
24494            )
24495        } else {
24496            None
24497        }
24498    }
24499
24500    pub fn render_crease_trailer(
24501        &self,
24502        buffer_row: MultiBufferRow,
24503        window: &mut Window,
24504        cx: &mut App,
24505    ) -> Option<AnyElement> {
24506        let folded = self.is_line_folded(buffer_row);
24507        if let Crease::Inline { render_trailer, .. } = self
24508            .crease_snapshot
24509            .query_row(buffer_row, self.buffer_snapshot())?
24510        {
24511            let render_trailer = render_trailer.as_ref()?;
24512            Some(render_trailer(buffer_row, folded, window, cx))
24513        } else {
24514            None
24515        }
24516    }
24517}
24518
24519impl Deref for EditorSnapshot {
24520    type Target = DisplaySnapshot;
24521
24522    fn deref(&self) -> &Self::Target {
24523        &self.display_snapshot
24524    }
24525}
24526
24527#[derive(Clone, Debug, PartialEq, Eq)]
24528pub enum EditorEvent {
24529    InputIgnored {
24530        text: Arc<str>,
24531    },
24532    InputHandled {
24533        utf16_range_to_replace: Option<Range<isize>>,
24534        text: Arc<str>,
24535    },
24536    ExcerptsAdded {
24537        buffer: Entity<Buffer>,
24538        predecessor: ExcerptId,
24539        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24540    },
24541    ExcerptsRemoved {
24542        ids: Vec<ExcerptId>,
24543        removed_buffer_ids: Vec<BufferId>,
24544    },
24545    BufferFoldToggled {
24546        ids: Vec<ExcerptId>,
24547        folded: bool,
24548    },
24549    ExcerptsEdited {
24550        ids: Vec<ExcerptId>,
24551    },
24552    ExcerptsExpanded {
24553        ids: Vec<ExcerptId>,
24554    },
24555    BufferEdited,
24556    Edited {
24557        transaction_id: clock::Lamport,
24558    },
24559    Reparsed(BufferId),
24560    Focused,
24561    FocusedIn,
24562    Blurred,
24563    DirtyChanged,
24564    Saved,
24565    TitleChanged,
24566    SelectionsChanged {
24567        local: bool,
24568    },
24569    ScrollPositionChanged {
24570        local: bool,
24571        autoscroll: bool,
24572    },
24573    TransactionUndone {
24574        transaction_id: clock::Lamport,
24575    },
24576    TransactionBegun {
24577        transaction_id: clock::Lamport,
24578    },
24579    CursorShapeChanged,
24580    BreadcrumbsChanged,
24581    PushedToNavHistory {
24582        anchor: Anchor,
24583        is_deactivate: bool,
24584    },
24585}
24586
24587impl EventEmitter<EditorEvent> for Editor {}
24588
24589impl Focusable for Editor {
24590    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24591        self.focus_handle.clone()
24592    }
24593}
24594
24595impl Render for Editor {
24596    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24597        let settings = ThemeSettings::get_global(cx);
24598
24599        let mut text_style = match self.mode {
24600            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24601                color: cx.theme().colors().editor_foreground,
24602                font_family: settings.ui_font.family.clone(),
24603                font_features: settings.ui_font.features.clone(),
24604                font_fallbacks: settings.ui_font.fallbacks.clone(),
24605                font_size: rems(0.875).into(),
24606                font_weight: settings.ui_font.weight,
24607                line_height: relative(settings.buffer_line_height.value()),
24608                ..Default::default()
24609            },
24610            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24611                color: cx.theme().colors().editor_foreground,
24612                font_family: settings.buffer_font.family.clone(),
24613                font_features: settings.buffer_font.features.clone(),
24614                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24615                font_size: settings.buffer_font_size(cx).into(),
24616                font_weight: settings.buffer_font.weight,
24617                line_height: relative(settings.buffer_line_height.value()),
24618                ..Default::default()
24619            },
24620        };
24621        if let Some(text_style_refinement) = &self.text_style_refinement {
24622            text_style.refine(text_style_refinement)
24623        }
24624
24625        let background = match self.mode {
24626            EditorMode::SingleLine => cx.theme().system().transparent,
24627            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24628            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24629            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24630        };
24631
24632        EditorElement::new(
24633            &cx.entity(),
24634            EditorStyle {
24635                background,
24636                border: cx.theme().colors().border,
24637                local_player: cx.theme().players().local(),
24638                text: text_style,
24639                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24640                syntax: cx.theme().syntax().clone(),
24641                status: cx.theme().status().clone(),
24642                inlay_hints_style: make_inlay_hints_style(cx),
24643                edit_prediction_styles: make_suggestion_styles(cx),
24644                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24645                show_underlines: self.diagnostics_enabled(),
24646            },
24647        )
24648    }
24649}
24650
24651impl EntityInputHandler for Editor {
24652    fn text_for_range(
24653        &mut self,
24654        range_utf16: Range<usize>,
24655        adjusted_range: &mut Option<Range<usize>>,
24656        _: &mut Window,
24657        cx: &mut Context<Self>,
24658    ) -> Option<String> {
24659        let snapshot = self.buffer.read(cx).read(cx);
24660        let start = snapshot.clip_offset_utf16(
24661            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
24662            Bias::Left,
24663        );
24664        let end = snapshot.clip_offset_utf16(
24665            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
24666            Bias::Right,
24667        );
24668        if (start.0.0..end.0.0) != range_utf16 {
24669            adjusted_range.replace(start.0.0..end.0.0);
24670        }
24671        Some(snapshot.text_for_range(start..end).collect())
24672    }
24673
24674    fn selected_text_range(
24675        &mut self,
24676        ignore_disabled_input: bool,
24677        _: &mut Window,
24678        cx: &mut Context<Self>,
24679    ) -> Option<UTF16Selection> {
24680        // Prevent the IME menu from appearing when holding down an alphabetic key
24681        // while input is disabled.
24682        if !ignore_disabled_input && !self.input_enabled {
24683            return None;
24684        }
24685
24686        let selection = self
24687            .selections
24688            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24689        let range = selection.range();
24690
24691        Some(UTF16Selection {
24692            range: range.start.0.0..range.end.0.0,
24693            reversed: selection.reversed,
24694        })
24695    }
24696
24697    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24698        let snapshot = self.buffer.read(cx).read(cx);
24699        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24700        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
24701    }
24702
24703    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24704        self.clear_highlights::<InputComposition>(cx);
24705        self.ime_transaction.take();
24706    }
24707
24708    fn replace_text_in_range(
24709        &mut self,
24710        range_utf16: Option<Range<usize>>,
24711        text: &str,
24712        window: &mut Window,
24713        cx: &mut Context<Self>,
24714    ) {
24715        if !self.input_enabled {
24716            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24717            return;
24718        }
24719
24720        self.transact(window, cx, |this, window, cx| {
24721            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24722                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24723                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24724                Some(this.selection_replacement_ranges(range_utf16, cx))
24725            } else {
24726                this.marked_text_ranges(cx)
24727            };
24728
24729            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24730                let newest_selection_id = this.selections.newest_anchor().id;
24731                this.selections
24732                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24733                    .iter()
24734                    .zip(ranges_to_replace.iter())
24735                    .find_map(|(selection, range)| {
24736                        if selection.id == newest_selection_id {
24737                            Some(
24738                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24739                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24740                            )
24741                        } else {
24742                            None
24743                        }
24744                    })
24745            });
24746
24747            cx.emit(EditorEvent::InputHandled {
24748                utf16_range_to_replace: range_to_replace,
24749                text: text.into(),
24750            });
24751
24752            if let Some(new_selected_ranges) = new_selected_ranges {
24753                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24754                    selections.select_ranges(new_selected_ranges)
24755                });
24756                this.backspace(&Default::default(), window, cx);
24757            }
24758
24759            this.handle_input(text, window, cx);
24760        });
24761
24762        if let Some(transaction) = self.ime_transaction {
24763            self.buffer.update(cx, |buffer, cx| {
24764                buffer.group_until_transaction(transaction, cx);
24765            });
24766        }
24767
24768        self.unmark_text(window, cx);
24769    }
24770
24771    fn replace_and_mark_text_in_range(
24772        &mut self,
24773        range_utf16: Option<Range<usize>>,
24774        text: &str,
24775        new_selected_range_utf16: Option<Range<usize>>,
24776        window: &mut Window,
24777        cx: &mut Context<Self>,
24778    ) {
24779        if !self.input_enabled {
24780            return;
24781        }
24782
24783        let transaction = self.transact(window, cx, |this, window, cx| {
24784            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24785                let snapshot = this.buffer.read(cx).read(cx);
24786                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24787                    for marked_range in &mut marked_ranges {
24788                        marked_range.end = marked_range.start + relative_range_utf16.end;
24789                        marked_range.start += relative_range_utf16.start;
24790                        marked_range.start =
24791                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24792                        marked_range.end =
24793                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24794                    }
24795                }
24796                Some(marked_ranges)
24797            } else if let Some(range_utf16) = range_utf16 {
24798                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24799                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24800                Some(this.selection_replacement_ranges(range_utf16, cx))
24801            } else {
24802                None
24803            };
24804
24805            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24806                let newest_selection_id = this.selections.newest_anchor().id;
24807                this.selections
24808                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24809                    .iter()
24810                    .zip(ranges_to_replace.iter())
24811                    .find_map(|(selection, range)| {
24812                        if selection.id == newest_selection_id {
24813                            Some(
24814                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24815                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24816                            )
24817                        } else {
24818                            None
24819                        }
24820                    })
24821            });
24822
24823            cx.emit(EditorEvent::InputHandled {
24824                utf16_range_to_replace: range_to_replace,
24825                text: text.into(),
24826            });
24827
24828            if let Some(ranges) = ranges_to_replace {
24829                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24830                    s.select_ranges(ranges)
24831                });
24832            }
24833
24834            let marked_ranges = {
24835                let snapshot = this.buffer.read(cx).read(cx);
24836                this.selections
24837                    .disjoint_anchors_arc()
24838                    .iter()
24839                    .map(|selection| {
24840                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24841                    })
24842                    .collect::<Vec<_>>()
24843            };
24844
24845            if text.is_empty() {
24846                this.unmark_text(window, cx);
24847            } else {
24848                this.highlight_text::<InputComposition>(
24849                    marked_ranges.clone(),
24850                    HighlightStyle {
24851                        underline: Some(UnderlineStyle {
24852                            thickness: px(1.),
24853                            color: None,
24854                            wavy: false,
24855                        }),
24856                        ..Default::default()
24857                    },
24858                    cx,
24859                );
24860            }
24861
24862            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24863            let use_autoclose = this.use_autoclose;
24864            let use_auto_surround = this.use_auto_surround;
24865            this.set_use_autoclose(false);
24866            this.set_use_auto_surround(false);
24867            this.handle_input(text, window, cx);
24868            this.set_use_autoclose(use_autoclose);
24869            this.set_use_auto_surround(use_auto_surround);
24870
24871            if let Some(new_selected_range) = new_selected_range_utf16 {
24872                let snapshot = this.buffer.read(cx).read(cx);
24873                let new_selected_ranges = marked_ranges
24874                    .into_iter()
24875                    .map(|marked_range| {
24876                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24877                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
24878                            insertion_start.0 + new_selected_range.start,
24879                        ));
24880                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
24881                            insertion_start.0 + new_selected_range.end,
24882                        ));
24883                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24884                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24885                    })
24886                    .collect::<Vec<_>>();
24887
24888                drop(snapshot);
24889                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24890                    selections.select_ranges(new_selected_ranges)
24891                });
24892            }
24893        });
24894
24895        self.ime_transaction = self.ime_transaction.or(transaction);
24896        if let Some(transaction) = self.ime_transaction {
24897            self.buffer.update(cx, |buffer, cx| {
24898                buffer.group_until_transaction(transaction, cx);
24899            });
24900        }
24901
24902        if self.text_highlights::<InputComposition>(cx).is_none() {
24903            self.ime_transaction.take();
24904        }
24905    }
24906
24907    fn bounds_for_range(
24908        &mut self,
24909        range_utf16: Range<usize>,
24910        element_bounds: gpui::Bounds<Pixels>,
24911        window: &mut Window,
24912        cx: &mut Context<Self>,
24913    ) -> Option<gpui::Bounds<Pixels>> {
24914        let text_layout_details = self.text_layout_details(window);
24915        let CharacterDimensions {
24916            em_width,
24917            em_advance,
24918            line_height,
24919        } = self.character_dimensions(window);
24920
24921        let snapshot = self.snapshot(window, cx);
24922        let scroll_position = snapshot.scroll_position();
24923        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24924
24925        let start =
24926            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
24927        let x = Pixels::from(
24928            ScrollOffset::from(
24929                snapshot.x_for_display_point(start, &text_layout_details)
24930                    + self.gutter_dimensions.full_width(),
24931            ) - scroll_left,
24932        );
24933        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24934
24935        Some(Bounds {
24936            origin: element_bounds.origin + point(x, y),
24937            size: size(em_width, line_height),
24938        })
24939    }
24940
24941    fn character_index_for_point(
24942        &mut self,
24943        point: gpui::Point<Pixels>,
24944        _window: &mut Window,
24945        _cx: &mut Context<Self>,
24946    ) -> Option<usize> {
24947        let position_map = self.last_position_map.as_ref()?;
24948        if !position_map.text_hitbox.contains(&point) {
24949            return None;
24950        }
24951        let display_point = position_map.point_for_position(point).previous_valid;
24952        let anchor = position_map
24953            .snapshot
24954            .display_point_to_anchor(display_point, Bias::Left);
24955        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24956        Some(utf16_offset.0.0)
24957    }
24958
24959    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24960        self.input_enabled
24961    }
24962}
24963
24964trait SelectionExt {
24965    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24966    fn spanned_rows(
24967        &self,
24968        include_end_if_at_line_start: bool,
24969        map: &DisplaySnapshot,
24970    ) -> Range<MultiBufferRow>;
24971}
24972
24973impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24974    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24975        let start = self
24976            .start
24977            .to_point(map.buffer_snapshot())
24978            .to_display_point(map);
24979        let end = self
24980            .end
24981            .to_point(map.buffer_snapshot())
24982            .to_display_point(map);
24983        if self.reversed {
24984            end..start
24985        } else {
24986            start..end
24987        }
24988    }
24989
24990    fn spanned_rows(
24991        &self,
24992        include_end_if_at_line_start: bool,
24993        map: &DisplaySnapshot,
24994    ) -> Range<MultiBufferRow> {
24995        let start = self.start.to_point(map.buffer_snapshot());
24996        let mut end = self.end.to_point(map.buffer_snapshot());
24997        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24998            end.row -= 1;
24999        }
25000
25001        let buffer_start = map.prev_line_boundary(start).0;
25002        let buffer_end = map.next_line_boundary(end).0;
25003        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25004    }
25005}
25006
25007impl<T: InvalidationRegion> InvalidationStack<T> {
25008    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25009    where
25010        S: Clone + ToOffset,
25011    {
25012        while let Some(region) = self.last() {
25013            let all_selections_inside_invalidation_ranges =
25014                if selections.len() == region.ranges().len() {
25015                    selections
25016                        .iter()
25017                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25018                        .all(|(selection, invalidation_range)| {
25019                            let head = selection.head().to_offset(buffer);
25020                            invalidation_range.start <= head && invalidation_range.end >= head
25021                        })
25022                } else {
25023                    false
25024                };
25025
25026            if all_selections_inside_invalidation_ranges {
25027                break;
25028            } else {
25029                self.pop();
25030            }
25031        }
25032    }
25033}
25034
25035impl<T> Default for InvalidationStack<T> {
25036    fn default() -> Self {
25037        Self(Default::default())
25038    }
25039}
25040
25041impl<T> Deref for InvalidationStack<T> {
25042    type Target = Vec<T>;
25043
25044    fn deref(&self) -> &Self::Target {
25045        &self.0
25046    }
25047}
25048
25049impl<T> DerefMut for InvalidationStack<T> {
25050    fn deref_mut(&mut self) -> &mut Self::Target {
25051        &mut self.0
25052    }
25053}
25054
25055impl InvalidationRegion for SnippetState {
25056    fn ranges(&self) -> &[Range<Anchor>] {
25057        &self.ranges[self.active_index]
25058    }
25059}
25060
25061fn edit_prediction_edit_text(
25062    current_snapshot: &BufferSnapshot,
25063    edits: &[(Range<Anchor>, impl AsRef<str>)],
25064    edit_preview: &EditPreview,
25065    include_deletions: bool,
25066    cx: &App,
25067) -> HighlightedText {
25068    let edits = edits
25069        .iter()
25070        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25071        .collect::<Vec<_>>();
25072
25073    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25074}
25075
25076fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25077    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25078    // Just show the raw edit text with basic styling
25079    let mut text = String::new();
25080    let mut highlights = Vec::new();
25081
25082    let insertion_highlight_style = HighlightStyle {
25083        color: Some(cx.theme().colors().text),
25084        ..Default::default()
25085    };
25086
25087    for (_, edit_text) in edits {
25088        let start_offset = text.len();
25089        text.push_str(edit_text);
25090        let end_offset = text.len();
25091
25092        if start_offset < end_offset {
25093            highlights.push((start_offset..end_offset, insertion_highlight_style));
25094        }
25095    }
25096
25097    HighlightedText {
25098        text: text.into(),
25099        highlights,
25100    }
25101}
25102
25103pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25104    match severity {
25105        lsp::DiagnosticSeverity::ERROR => colors.error,
25106        lsp::DiagnosticSeverity::WARNING => colors.warning,
25107        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25108        lsp::DiagnosticSeverity::HINT => colors.info,
25109        _ => colors.ignored,
25110    }
25111}
25112
25113pub fn styled_runs_for_code_label<'a>(
25114    label: &'a CodeLabel,
25115    syntax_theme: &'a theme::SyntaxTheme,
25116    local_player: &'a theme::PlayerColor,
25117) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25118    let fade_out = HighlightStyle {
25119        fade_out: Some(0.35),
25120        ..Default::default()
25121    };
25122
25123    let mut prev_end = label.filter_range.end;
25124    label
25125        .runs
25126        .iter()
25127        .enumerate()
25128        .flat_map(move |(ix, (range, highlight_id))| {
25129            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25130                HighlightStyle {
25131                    color: Some(local_player.cursor),
25132                    ..Default::default()
25133                }
25134            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25135                HighlightStyle {
25136                    background_color: Some(local_player.selection),
25137                    ..Default::default()
25138                }
25139            } else if let Some(style) = highlight_id.style(syntax_theme) {
25140                style
25141            } else {
25142                return Default::default();
25143            };
25144            let muted_style = style.highlight(fade_out);
25145
25146            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25147            if range.start >= label.filter_range.end {
25148                if range.start > prev_end {
25149                    runs.push((prev_end..range.start, fade_out));
25150                }
25151                runs.push((range.clone(), muted_style));
25152            } else if range.end <= label.filter_range.end {
25153                runs.push((range.clone(), style));
25154            } else {
25155                runs.push((range.start..label.filter_range.end, style));
25156                runs.push((label.filter_range.end..range.end, muted_style));
25157            }
25158            prev_end = cmp::max(prev_end, range.end);
25159
25160            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25161                runs.push((prev_end..label.text.len(), fade_out));
25162            }
25163
25164            runs
25165        })
25166}
25167
25168pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25169    let mut prev_index = 0;
25170    let mut prev_codepoint: Option<char> = None;
25171    text.char_indices()
25172        .chain([(text.len(), '\0')])
25173        .filter_map(move |(index, codepoint)| {
25174            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25175            let is_boundary = index == text.len()
25176                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25177                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25178            if is_boundary {
25179                let chunk = &text[prev_index..index];
25180                prev_index = index;
25181                Some(chunk)
25182            } else {
25183                None
25184            }
25185        })
25186}
25187
25188/// Given a string of text immediately before the cursor, iterates over possible
25189/// strings a snippet could match to. More precisely: returns an iterator over
25190/// suffixes of `text` created by splitting at word boundaries (before & after
25191/// every non-word character).
25192///
25193/// Shorter suffixes are returned first.
25194pub(crate) fn snippet_candidate_suffixes(
25195    text: &str,
25196    is_word_char: impl Fn(char) -> bool,
25197) -> impl std::iter::Iterator<Item = &str> {
25198    let mut prev_index = text.len();
25199    let mut prev_codepoint = None;
25200    text.char_indices()
25201        .rev()
25202        .chain([(0, '\0')])
25203        .filter_map(move |(index, codepoint)| {
25204            let prev_index = std::mem::replace(&mut prev_index, index);
25205            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25206            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25207                None
25208            } else {
25209                let chunk = &text[prev_index..]; // go to end of string
25210                Some(chunk)
25211            }
25212        })
25213}
25214
25215pub trait RangeToAnchorExt: Sized {
25216    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25217
25218    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25219        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25220        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25221    }
25222}
25223
25224impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25225    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25226        let start_offset = self.start.to_offset(snapshot);
25227        let end_offset = self.end.to_offset(snapshot);
25228        if start_offset == end_offset {
25229            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25230        } else {
25231            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25232        }
25233    }
25234}
25235
25236pub trait RowExt {
25237    fn as_f64(&self) -> f64;
25238
25239    fn next_row(&self) -> Self;
25240
25241    fn previous_row(&self) -> Self;
25242
25243    fn minus(&self, other: Self) -> u32;
25244}
25245
25246impl RowExt for DisplayRow {
25247    fn as_f64(&self) -> f64 {
25248        self.0 as _
25249    }
25250
25251    fn next_row(&self) -> Self {
25252        Self(self.0 + 1)
25253    }
25254
25255    fn previous_row(&self) -> Self {
25256        Self(self.0.saturating_sub(1))
25257    }
25258
25259    fn minus(&self, other: Self) -> u32 {
25260        self.0 - other.0
25261    }
25262}
25263
25264impl RowExt for MultiBufferRow {
25265    fn as_f64(&self) -> f64 {
25266        self.0 as _
25267    }
25268
25269    fn next_row(&self) -> Self {
25270        Self(self.0 + 1)
25271    }
25272
25273    fn previous_row(&self) -> Self {
25274        Self(self.0.saturating_sub(1))
25275    }
25276
25277    fn minus(&self, other: Self) -> u32 {
25278        self.0 - other.0
25279    }
25280}
25281
25282trait RowRangeExt {
25283    type Row;
25284
25285    fn len(&self) -> usize;
25286
25287    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25288}
25289
25290impl RowRangeExt for Range<MultiBufferRow> {
25291    type Row = MultiBufferRow;
25292
25293    fn len(&self) -> usize {
25294        (self.end.0 - self.start.0) as usize
25295    }
25296
25297    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25298        (self.start.0..self.end.0).map(MultiBufferRow)
25299    }
25300}
25301
25302impl RowRangeExt for Range<DisplayRow> {
25303    type Row = DisplayRow;
25304
25305    fn len(&self) -> usize {
25306        (self.end.0 - self.start.0) as usize
25307    }
25308
25309    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25310        (self.start.0..self.end.0).map(DisplayRow)
25311    }
25312}
25313
25314/// If select range has more than one line, we
25315/// just point the cursor to range.start.
25316fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25317    if range.start.row == range.end.row {
25318        range
25319    } else {
25320        range.start..range.start
25321    }
25322}
25323pub struct KillRing(ClipboardItem);
25324impl Global for KillRing {}
25325
25326const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25327
25328enum BreakpointPromptEditAction {
25329    Log,
25330    Condition,
25331    HitCondition,
25332}
25333
25334struct BreakpointPromptEditor {
25335    pub(crate) prompt: Entity<Editor>,
25336    editor: WeakEntity<Editor>,
25337    breakpoint_anchor: Anchor,
25338    breakpoint: Breakpoint,
25339    edit_action: BreakpointPromptEditAction,
25340    block_ids: HashSet<CustomBlockId>,
25341    editor_margins: Arc<Mutex<EditorMargins>>,
25342    _subscriptions: Vec<Subscription>,
25343}
25344
25345impl BreakpointPromptEditor {
25346    const MAX_LINES: u8 = 4;
25347
25348    fn new(
25349        editor: WeakEntity<Editor>,
25350        breakpoint_anchor: Anchor,
25351        breakpoint: Breakpoint,
25352        edit_action: BreakpointPromptEditAction,
25353        window: &mut Window,
25354        cx: &mut Context<Self>,
25355    ) -> Self {
25356        let base_text = match edit_action {
25357            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25358            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25359            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25360        }
25361        .map(|msg| msg.to_string())
25362        .unwrap_or_default();
25363
25364        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25365        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25366
25367        let prompt = cx.new(|cx| {
25368            let mut prompt = Editor::new(
25369                EditorMode::AutoHeight {
25370                    min_lines: 1,
25371                    max_lines: Some(Self::MAX_LINES as usize),
25372                },
25373                buffer,
25374                None,
25375                window,
25376                cx,
25377            );
25378            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25379            prompt.set_show_cursor_when_unfocused(false, cx);
25380            prompt.set_placeholder_text(
25381                match edit_action {
25382                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25383                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25384                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25385                },
25386                window,
25387                cx,
25388            );
25389
25390            prompt
25391        });
25392
25393        Self {
25394            prompt,
25395            editor,
25396            breakpoint_anchor,
25397            breakpoint,
25398            edit_action,
25399            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25400            block_ids: Default::default(),
25401            _subscriptions: vec![],
25402        }
25403    }
25404
25405    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25406        self.block_ids.extend(block_ids)
25407    }
25408
25409    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25410        if let Some(editor) = self.editor.upgrade() {
25411            let message = self
25412                .prompt
25413                .read(cx)
25414                .buffer
25415                .read(cx)
25416                .as_singleton()
25417                .expect("A multi buffer in breakpoint prompt isn't possible")
25418                .read(cx)
25419                .as_rope()
25420                .to_string();
25421
25422            editor.update(cx, |editor, cx| {
25423                editor.edit_breakpoint_at_anchor(
25424                    self.breakpoint_anchor,
25425                    self.breakpoint.clone(),
25426                    match self.edit_action {
25427                        BreakpointPromptEditAction::Log => {
25428                            BreakpointEditAction::EditLogMessage(message.into())
25429                        }
25430                        BreakpointPromptEditAction::Condition => {
25431                            BreakpointEditAction::EditCondition(message.into())
25432                        }
25433                        BreakpointPromptEditAction::HitCondition => {
25434                            BreakpointEditAction::EditHitCondition(message.into())
25435                        }
25436                    },
25437                    cx,
25438                );
25439
25440                editor.remove_blocks(self.block_ids.clone(), None, cx);
25441                cx.focus_self(window);
25442            });
25443        }
25444    }
25445
25446    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25447        self.editor
25448            .update(cx, |editor, cx| {
25449                editor.remove_blocks(self.block_ids.clone(), None, cx);
25450                window.focus(&editor.focus_handle);
25451            })
25452            .log_err();
25453    }
25454
25455    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25456        let settings = ThemeSettings::get_global(cx);
25457        let text_style = TextStyle {
25458            color: if self.prompt.read(cx).read_only(cx) {
25459                cx.theme().colors().text_disabled
25460            } else {
25461                cx.theme().colors().text
25462            },
25463            font_family: settings.buffer_font.family.clone(),
25464            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25465            font_size: settings.buffer_font_size(cx).into(),
25466            font_weight: settings.buffer_font.weight,
25467            line_height: relative(settings.buffer_line_height.value()),
25468            ..Default::default()
25469        };
25470        EditorElement::new(
25471            &self.prompt,
25472            EditorStyle {
25473                background: cx.theme().colors().editor_background,
25474                local_player: cx.theme().players().local(),
25475                text: text_style,
25476                ..Default::default()
25477            },
25478        )
25479    }
25480}
25481
25482impl Render for BreakpointPromptEditor {
25483    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25484        let editor_margins = *self.editor_margins.lock();
25485        let gutter_dimensions = editor_margins.gutter;
25486        h_flex()
25487            .key_context("Editor")
25488            .bg(cx.theme().colors().editor_background)
25489            .border_y_1()
25490            .border_color(cx.theme().status().info_border)
25491            .size_full()
25492            .py(window.line_height() / 2.5)
25493            .on_action(cx.listener(Self::confirm))
25494            .on_action(cx.listener(Self::cancel))
25495            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25496            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25497    }
25498}
25499
25500impl Focusable for BreakpointPromptEditor {
25501    fn focus_handle(&self, cx: &App) -> FocusHandle {
25502        self.prompt.focus_handle(cx)
25503    }
25504}
25505
25506fn all_edits_insertions_or_deletions(
25507    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25508    snapshot: &MultiBufferSnapshot,
25509) -> bool {
25510    let mut all_insertions = true;
25511    let mut all_deletions = true;
25512
25513    for (range, new_text) in edits.iter() {
25514        let range_is_empty = range.to_offset(snapshot).is_empty();
25515        let text_is_empty = new_text.is_empty();
25516
25517        if range_is_empty != text_is_empty {
25518            if range_is_empty {
25519                all_deletions = false;
25520            } else {
25521                all_insertions = false;
25522            }
25523        } else {
25524            return false;
25525        }
25526
25527        if !all_insertions && !all_deletions {
25528            return false;
25529        }
25530    }
25531    all_insertions || all_deletions
25532}
25533
25534struct MissingEditPredictionKeybindingTooltip;
25535
25536impl Render for MissingEditPredictionKeybindingTooltip {
25537    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25538        ui::tooltip_container(cx, |container, cx| {
25539            container
25540                .flex_shrink_0()
25541                .max_w_80()
25542                .min_h(rems_from_px(124.))
25543                .justify_between()
25544                .child(
25545                    v_flex()
25546                        .flex_1()
25547                        .text_ui_sm(cx)
25548                        .child(Label::new("Conflict with Accept Keybinding"))
25549                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25550                )
25551                .child(
25552                    h_flex()
25553                        .pb_1()
25554                        .gap_1()
25555                        .items_end()
25556                        .w_full()
25557                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25558                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25559                        }))
25560                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25561                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25562                        })),
25563                )
25564        })
25565    }
25566}
25567
25568#[derive(Debug, Clone, Copy, PartialEq)]
25569pub struct LineHighlight {
25570    pub background: Background,
25571    pub border: Option<gpui::Hsla>,
25572    pub include_gutter: bool,
25573    pub type_id: Option<TypeId>,
25574}
25575
25576struct LineManipulationResult {
25577    pub new_text: String,
25578    pub line_count_before: usize,
25579    pub line_count_after: usize,
25580}
25581
25582fn render_diff_hunk_controls(
25583    row: u32,
25584    status: &DiffHunkStatus,
25585    hunk_range: Range<Anchor>,
25586    is_created_file: bool,
25587    line_height: Pixels,
25588    editor: &Entity<Editor>,
25589    _window: &mut Window,
25590    cx: &mut App,
25591) -> AnyElement {
25592    h_flex()
25593        .h(line_height)
25594        .mr_1()
25595        .gap_1()
25596        .px_0p5()
25597        .pb_1()
25598        .border_x_1()
25599        .border_b_1()
25600        .border_color(cx.theme().colors().border_variant)
25601        .rounded_b_lg()
25602        .bg(cx.theme().colors().editor_background)
25603        .gap_1()
25604        .block_mouse_except_scroll()
25605        .shadow_md()
25606        .child(if status.has_secondary_hunk() {
25607            Button::new(("stage", row as u64), "Stage")
25608                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25609                .tooltip({
25610                    let focus_handle = editor.focus_handle(cx);
25611                    move |_window, cx| {
25612                        Tooltip::for_action_in(
25613                            "Stage Hunk",
25614                            &::git::ToggleStaged,
25615                            &focus_handle,
25616                            cx,
25617                        )
25618                    }
25619                })
25620                .on_click({
25621                    let editor = editor.clone();
25622                    move |_event, _window, cx| {
25623                        editor.update(cx, |editor, cx| {
25624                            editor.stage_or_unstage_diff_hunks(
25625                                true,
25626                                vec![hunk_range.start..hunk_range.start],
25627                                cx,
25628                            );
25629                        });
25630                    }
25631                })
25632        } else {
25633            Button::new(("unstage", row as u64), "Unstage")
25634                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25635                .tooltip({
25636                    let focus_handle = editor.focus_handle(cx);
25637                    move |_window, cx| {
25638                        Tooltip::for_action_in(
25639                            "Unstage Hunk",
25640                            &::git::ToggleStaged,
25641                            &focus_handle,
25642                            cx,
25643                        )
25644                    }
25645                })
25646                .on_click({
25647                    let editor = editor.clone();
25648                    move |_event, _window, cx| {
25649                        editor.update(cx, |editor, cx| {
25650                            editor.stage_or_unstage_diff_hunks(
25651                                false,
25652                                vec![hunk_range.start..hunk_range.start],
25653                                cx,
25654                            );
25655                        });
25656                    }
25657                })
25658        })
25659        .child(
25660            Button::new(("restore", row as u64), "Restore")
25661                .tooltip({
25662                    let focus_handle = editor.focus_handle(cx);
25663                    move |_window, cx| {
25664                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25665                    }
25666                })
25667                .on_click({
25668                    let editor = editor.clone();
25669                    move |_event, window, cx| {
25670                        editor.update(cx, |editor, cx| {
25671                            let snapshot = editor.snapshot(window, cx);
25672                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25673                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25674                        });
25675                    }
25676                })
25677                .disabled(is_created_file),
25678        )
25679        .when(
25680            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25681            |el| {
25682                el.child(
25683                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25684                        .shape(IconButtonShape::Square)
25685                        .icon_size(IconSize::Small)
25686                        // .disabled(!has_multiple_hunks)
25687                        .tooltip({
25688                            let focus_handle = editor.focus_handle(cx);
25689                            move |_window, cx| {
25690                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25691                            }
25692                        })
25693                        .on_click({
25694                            let editor = editor.clone();
25695                            move |_event, window, cx| {
25696                                editor.update(cx, |editor, cx| {
25697                                    let snapshot = editor.snapshot(window, cx);
25698                                    let position =
25699                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25700                                    editor.go_to_hunk_before_or_after_position(
25701                                        &snapshot,
25702                                        position,
25703                                        Direction::Next,
25704                                        window,
25705                                        cx,
25706                                    );
25707                                    editor.expand_selected_diff_hunks(cx);
25708                                });
25709                            }
25710                        }),
25711                )
25712                .child(
25713                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25714                        .shape(IconButtonShape::Square)
25715                        .icon_size(IconSize::Small)
25716                        // .disabled(!has_multiple_hunks)
25717                        .tooltip({
25718                            let focus_handle = editor.focus_handle(cx);
25719                            move |_window, cx| {
25720                                Tooltip::for_action_in(
25721                                    "Previous Hunk",
25722                                    &GoToPreviousHunk,
25723                                    &focus_handle,
25724                                    cx,
25725                                )
25726                            }
25727                        })
25728                        .on_click({
25729                            let editor = editor.clone();
25730                            move |_event, window, cx| {
25731                                editor.update(cx, |editor, cx| {
25732                                    let snapshot = editor.snapshot(window, cx);
25733                                    let point =
25734                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25735                                    editor.go_to_hunk_before_or_after_position(
25736                                        &snapshot,
25737                                        point,
25738                                        Direction::Prev,
25739                                        window,
25740                                        cx,
25741                                    );
25742                                    editor.expand_selected_diff_hunks(cx);
25743                                });
25744                            }
25745                        }),
25746                )
25747            },
25748        )
25749        .into_any_element()
25750}
25751
25752pub fn multibuffer_context_lines(cx: &App) -> u32 {
25753    EditorSettings::try_get(cx)
25754        .map(|settings| settings.excerpt_context_lines)
25755        .unwrap_or(2)
25756        .min(32)
25757}