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::{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    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 = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  730type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  731
  732#[derive(Default)]
  733struct ScrollbarMarkerState {
  734    scrollbar_size: Size<Pixels>,
  735    dirty: bool,
  736    markers: Arc<[PaintQuad]>,
  737    pending_refresh: Option<Task<Result<()>>>,
  738}
  739
  740impl ScrollbarMarkerState {
  741    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  742        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  743    }
  744}
  745
  746#[derive(Clone, Copy, PartialEq, Eq)]
  747pub enum MinimapVisibility {
  748    Disabled,
  749    Enabled {
  750        /// The configuration currently present in the users settings.
  751        setting_configuration: bool,
  752        /// Whether to override the currently set visibility from the users setting.
  753        toggle_override: bool,
  754    },
  755}
  756
  757impl MinimapVisibility {
  758    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  759        if mode.is_full() {
  760            Self::Enabled {
  761                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  762                toggle_override: false,
  763            }
  764        } else {
  765            Self::Disabled
  766        }
  767    }
  768
  769    fn hidden(&self) -> Self {
  770        match *self {
  771            Self::Enabled {
  772                setting_configuration,
  773                ..
  774            } => Self::Enabled {
  775                setting_configuration,
  776                toggle_override: setting_configuration,
  777            },
  778            Self::Disabled => Self::Disabled,
  779        }
  780    }
  781
  782    fn disabled(&self) -> bool {
  783        matches!(*self, Self::Disabled)
  784    }
  785
  786    fn settings_visibility(&self) -> bool {
  787        match *self {
  788            Self::Enabled {
  789                setting_configuration,
  790                ..
  791            } => setting_configuration,
  792            _ => false,
  793        }
  794    }
  795
  796    fn visible(&self) -> bool {
  797        match *self {
  798            Self::Enabled {
  799                setting_configuration,
  800                toggle_override,
  801            } => setting_configuration ^ toggle_override,
  802            _ => false,
  803        }
  804    }
  805
  806    fn toggle_visibility(&self) -> Self {
  807        match *self {
  808            Self::Enabled {
  809                toggle_override,
  810                setting_configuration,
  811            } => Self::Enabled {
  812                setting_configuration,
  813                toggle_override: !toggle_override,
  814            },
  815            Self::Disabled => Self::Disabled,
  816        }
  817    }
  818}
  819
  820#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  821pub enum BufferSerialization {
  822    All,
  823    NonDirtyBuffers,
  824}
  825
  826impl BufferSerialization {
  827    fn new(restore_unsaved_buffers: bool) -> Self {
  828        if restore_unsaved_buffers {
  829            Self::All
  830        } else {
  831            Self::NonDirtyBuffers
  832        }
  833    }
  834}
  835
  836#[derive(Clone, Debug)]
  837struct RunnableTasks {
  838    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  839    offset: multi_buffer::Anchor,
  840    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  841    column: u32,
  842    // Values of all named captures, including those starting with '_'
  843    extra_variables: HashMap<String, String>,
  844    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  845    context_range: Range<BufferOffset>,
  846}
  847
  848impl RunnableTasks {
  849    fn resolve<'a>(
  850        &'a self,
  851        cx: &'a task::TaskContext,
  852    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  853        self.templates.iter().filter_map(|(kind, template)| {
  854            template
  855                .resolve_task(&kind.to_id_base(), cx)
  856                .map(|task| (kind.clone(), task))
  857        })
  858    }
  859}
  860
  861#[derive(Clone)]
  862pub struct ResolvedTasks {
  863    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  864    position: Anchor,
  865}
  866
  867/// Addons allow storing per-editor state in other crates (e.g. Vim)
  868pub trait Addon: 'static {
  869    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  870
  871    fn render_buffer_header_controls(
  872        &self,
  873        _: &ExcerptInfo,
  874        _: &Window,
  875        _: &App,
  876    ) -> Option<AnyElement> {
  877        None
  878    }
  879
  880    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  881        None
  882    }
  883
  884    fn to_any(&self) -> &dyn std::any::Any;
  885
  886    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  887        None
  888    }
  889}
  890
  891struct ChangeLocation {
  892    current: Option<Vec<Anchor>>,
  893    original: Vec<Anchor>,
  894}
  895impl ChangeLocation {
  896    fn locations(&self) -> &[Anchor] {
  897        self.current.as_ref().unwrap_or(&self.original)
  898    }
  899}
  900
  901/// A set of caret positions, registered when the editor was edited.
  902pub struct ChangeList {
  903    changes: Vec<ChangeLocation>,
  904    /// Currently "selected" change.
  905    position: Option<usize>,
  906}
  907
  908impl ChangeList {
  909    pub fn new() -> Self {
  910        Self {
  911            changes: Vec::new(),
  912            position: None,
  913        }
  914    }
  915
  916    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  917    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  918    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  919        if self.changes.is_empty() {
  920            return None;
  921        }
  922
  923        let prev = self.position.unwrap_or(self.changes.len());
  924        let next = if direction == Direction::Prev {
  925            prev.saturating_sub(count)
  926        } else {
  927            (prev + count).min(self.changes.len() - 1)
  928        };
  929        self.position = Some(next);
  930        self.changes.get(next).map(|change| change.locations())
  931    }
  932
  933    /// Adds a new change to the list, resetting the change list position.
  934    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  935        self.position.take();
  936        if let Some(last) = self.changes.last_mut()
  937            && group
  938        {
  939            last.current = Some(new_positions)
  940        } else {
  941            self.changes.push(ChangeLocation {
  942                original: new_positions,
  943                current: None,
  944            });
  945        }
  946    }
  947
  948    pub fn last(&self) -> Option<&[Anchor]> {
  949        self.changes.last().map(|change| change.locations())
  950    }
  951
  952    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  953        self.changes.last().map(|change| change.original.as_slice())
  954    }
  955
  956    pub fn invert_last_group(&mut self) {
  957        if let Some(last) = self.changes.last_mut()
  958            && let Some(current) = last.current.as_mut()
  959        {
  960            mem::swap(&mut last.original, current);
  961        }
  962    }
  963}
  964
  965#[derive(Clone)]
  966struct InlineBlamePopoverState {
  967    scroll_handle: ScrollHandle,
  968    commit_message: Option<ParsedCommitMessage>,
  969    markdown: Entity<Markdown>,
  970}
  971
  972struct InlineBlamePopover {
  973    position: gpui::Point<Pixels>,
  974    hide_task: Option<Task<()>>,
  975    popover_bounds: Option<Bounds<Pixels>>,
  976    popover_state: InlineBlamePopoverState,
  977    keyboard_grace: bool,
  978}
  979
  980enum SelectionDragState {
  981    /// State when no drag related activity is detected.
  982    None,
  983    /// State when the mouse is down on a selection that is about to be dragged.
  984    ReadyToDrag {
  985        selection: Selection<Anchor>,
  986        click_position: gpui::Point<Pixels>,
  987        mouse_down_time: Instant,
  988    },
  989    /// State when the mouse is dragging the selection in the editor.
  990    Dragging {
  991        selection: Selection<Anchor>,
  992        drop_cursor: Selection<Anchor>,
  993        hide_drop_cursor: bool,
  994    },
  995}
  996
  997enum ColumnarSelectionState {
  998    FromMouse {
  999        selection_tail: Anchor,
 1000        display_point: Option<DisplayPoint>,
 1001    },
 1002    FromSelection {
 1003        selection_tail: Anchor,
 1004    },
 1005}
 1006
 1007/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1008/// a breakpoint on them.
 1009#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1010struct PhantomBreakpointIndicator {
 1011    display_row: DisplayRow,
 1012    /// There's a small debounce between hovering over the line and showing the indicator.
 1013    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1014    is_active: bool,
 1015    collides_with_existing_breakpoint: bool,
 1016}
 1017
 1018/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1019///
 1020/// See the [module level documentation](self) for more information.
 1021pub struct Editor {
 1022    focus_handle: FocusHandle,
 1023    last_focused_descendant: Option<WeakFocusHandle>,
 1024    /// The text buffer being edited
 1025    buffer: Entity<MultiBuffer>,
 1026    /// Map of how text in the buffer should be displayed.
 1027    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1028    pub display_map: Entity<DisplayMap>,
 1029    placeholder_display_map: Option<Entity<DisplayMap>>,
 1030    pub selections: SelectionsCollection,
 1031    pub scroll_manager: ScrollManager,
 1032    /// When inline assist editors are linked, they all render cursors because
 1033    /// typing enters text into each of them, even the ones that aren't focused.
 1034    pub(crate) show_cursor_when_unfocused: bool,
 1035    columnar_selection_state: Option<ColumnarSelectionState>,
 1036    add_selections_state: Option<AddSelectionsState>,
 1037    select_next_state: Option<SelectNextState>,
 1038    select_prev_state: Option<SelectNextState>,
 1039    selection_history: SelectionHistory,
 1040    defer_selection_effects: bool,
 1041    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1042    autoclose_regions: Vec<AutocloseRegion>,
 1043    snippet_stack: InvalidationStack<SnippetState>,
 1044    select_syntax_node_history: SelectSyntaxNodeHistory,
 1045    ime_transaction: Option<TransactionId>,
 1046    pub diagnostics_max_severity: DiagnosticSeverity,
 1047    active_diagnostics: ActiveDiagnostic,
 1048    show_inline_diagnostics: bool,
 1049    inline_diagnostics_update: Task<()>,
 1050    inline_diagnostics_enabled: bool,
 1051    diagnostics_enabled: bool,
 1052    word_completions_enabled: bool,
 1053    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1054    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1055    hard_wrap: Option<usize>,
 1056    project: Option<Entity<Project>>,
 1057    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1058    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1059    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1060    blink_manager: Entity<BlinkManager>,
 1061    show_cursor_names: bool,
 1062    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1063    pub show_local_selections: bool,
 1064    mode: EditorMode,
 1065    show_breadcrumbs: bool,
 1066    show_gutter: bool,
 1067    show_scrollbars: ScrollbarAxes,
 1068    minimap_visibility: MinimapVisibility,
 1069    offset_content: bool,
 1070    disable_expand_excerpt_buttons: bool,
 1071    show_line_numbers: Option<bool>,
 1072    use_relative_line_numbers: Option<bool>,
 1073    show_git_diff_gutter: Option<bool>,
 1074    show_code_actions: Option<bool>,
 1075    show_runnables: Option<bool>,
 1076    show_breakpoints: Option<bool>,
 1077    show_wrap_guides: Option<bool>,
 1078    show_indent_guides: Option<bool>,
 1079    highlight_order: usize,
 1080    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1081    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1082    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1083    scrollbar_marker_state: ScrollbarMarkerState,
 1084    active_indent_guides_state: ActiveIndentGuidesState,
 1085    nav_history: Option<ItemNavHistory>,
 1086    context_menu: RefCell<Option<CodeContextMenu>>,
 1087    context_menu_options: Option<ContextMenuOptions>,
 1088    mouse_context_menu: Option<MouseContextMenu>,
 1089    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1090    inline_blame_popover: Option<InlineBlamePopover>,
 1091    inline_blame_popover_show_task: Option<Task<()>>,
 1092    signature_help_state: SignatureHelpState,
 1093    auto_signature_help: Option<bool>,
 1094    find_all_references_task_sources: Vec<Anchor>,
 1095    next_completion_id: CompletionId,
 1096    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1097    code_actions_task: Option<Task<Result<()>>>,
 1098    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1099    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1100    document_highlights_task: Option<Task<()>>,
 1101    linked_editing_range_task: Option<Task<Option<()>>>,
 1102    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1103    pending_rename: Option<RenameState>,
 1104    searchable: bool,
 1105    cursor_shape: CursorShape,
 1106    current_line_highlight: Option<CurrentLineHighlight>,
 1107    pub collapse_matches: bool,
 1108    autoindent_mode: Option<AutoindentMode>,
 1109    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1110    input_enabled: bool,
 1111    use_modal_editing: bool,
 1112    read_only: bool,
 1113    leader_id: Option<CollaboratorId>,
 1114    remote_id: Option<ViewId>,
 1115    pub hover_state: HoverState,
 1116    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1117    gutter_hovered: bool,
 1118    hovered_link_state: Option<HoveredLinkState>,
 1119    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1120    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1121    active_edit_prediction: Option<EditPredictionState>,
 1122    /// Used to prevent flickering as the user types while the menu is open
 1123    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1124    edit_prediction_settings: EditPredictionSettings,
 1125    edit_predictions_hidden_for_vim_mode: bool,
 1126    show_edit_predictions_override: Option<bool>,
 1127    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1128    edit_prediction_preview: EditPredictionPreview,
 1129    edit_prediction_indent_conflict: bool,
 1130    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1131    next_inlay_id: usize,
 1132    next_color_inlay_id: usize,
 1133    _subscriptions: Vec<Subscription>,
 1134    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1135    gutter_dimensions: GutterDimensions,
 1136    style: Option<EditorStyle>,
 1137    text_style_refinement: Option<TextStyleRefinement>,
 1138    next_editor_action_id: EditorActionId,
 1139    editor_actions: Rc<
 1140        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1141    >,
 1142    use_autoclose: bool,
 1143    use_auto_surround: bool,
 1144    auto_replace_emoji_shortcode: bool,
 1145    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1146    show_git_blame_gutter: bool,
 1147    show_git_blame_inline: bool,
 1148    show_git_blame_inline_delay_task: Option<Task<()>>,
 1149    git_blame_inline_enabled: bool,
 1150    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1151    buffer_serialization: Option<BufferSerialization>,
 1152    show_selection_menu: Option<bool>,
 1153    blame: Option<Entity<GitBlame>>,
 1154    blame_subscription: Option<Subscription>,
 1155    custom_context_menu: Option<
 1156        Box<
 1157            dyn 'static
 1158                + Fn(
 1159                    &mut Self,
 1160                    DisplayPoint,
 1161                    &mut Window,
 1162                    &mut Context<Self>,
 1163                ) -> Option<Entity<ui::ContextMenu>>,
 1164        >,
 1165    >,
 1166    last_bounds: Option<Bounds<Pixels>>,
 1167    last_position_map: Option<Rc<PositionMap>>,
 1168    expect_bounds_change: Option<Bounds<Pixels>>,
 1169    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1170    tasks_update_task: Option<Task<()>>,
 1171    breakpoint_store: Option<Entity<BreakpointStore>>,
 1172    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1173    hovered_diff_hunk_row: Option<DisplayRow>,
 1174    pull_diagnostics_task: Task<()>,
 1175    in_project_search: bool,
 1176    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1177    breadcrumb_header: Option<String>,
 1178    focused_block: Option<FocusedBlock>,
 1179    next_scroll_position: NextScrollCursorCenterTopBottom,
 1180    addons: HashMap<TypeId, Box<dyn Addon>>,
 1181    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1182    load_diff_task: Option<Shared<Task<()>>>,
 1183    /// Whether we are temporarily displaying a diff other than git's
 1184    temporary_diff_override: bool,
 1185    selection_mark_mode: bool,
 1186    toggle_fold_multiple_buffers: Task<()>,
 1187    _scroll_cursor_center_top_bottom_task: Task<()>,
 1188    serialize_selections: Task<()>,
 1189    serialize_folds: Task<()>,
 1190    mouse_cursor_hidden: bool,
 1191    minimap: Option<Entity<Self>>,
 1192    hide_mouse_mode: HideMouseMode,
 1193    pub change_list: ChangeList,
 1194    inline_value_cache: InlineValueCache,
 1195
 1196    selection_drag_state: SelectionDragState,
 1197    colors: Option<LspColorData>,
 1198    post_scroll_update: Task<()>,
 1199    refresh_colors_task: Task<()>,
 1200    inlay_hints: Option<LspInlayHintData>,
 1201    folding_newlines: Task<()>,
 1202    select_next_is_case_sensitive: Option<bool>,
 1203    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1204    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1205    accent_overrides: Vec<SharedString>,
 1206    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1207}
 1208
 1209fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1210    if debounce_ms > 0 {
 1211        Some(Duration::from_millis(debounce_ms))
 1212    } else {
 1213        None
 1214    }
 1215}
 1216
 1217#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1218enum NextScrollCursorCenterTopBottom {
 1219    #[default]
 1220    Center,
 1221    Top,
 1222    Bottom,
 1223}
 1224
 1225impl NextScrollCursorCenterTopBottom {
 1226    fn next(&self) -> Self {
 1227        match self {
 1228            Self::Center => Self::Top,
 1229            Self::Top => Self::Bottom,
 1230            Self::Bottom => Self::Center,
 1231        }
 1232    }
 1233}
 1234
 1235#[derive(Clone)]
 1236pub struct EditorSnapshot {
 1237    pub mode: EditorMode,
 1238    show_gutter: bool,
 1239    show_line_numbers: Option<bool>,
 1240    show_git_diff_gutter: Option<bool>,
 1241    show_code_actions: Option<bool>,
 1242    show_runnables: Option<bool>,
 1243    show_breakpoints: Option<bool>,
 1244    git_blame_gutter_max_author_length: Option<usize>,
 1245    pub display_snapshot: DisplaySnapshot,
 1246    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1247    is_focused: bool,
 1248    scroll_anchor: ScrollAnchor,
 1249    ongoing_scroll: OngoingScroll,
 1250    current_line_highlight: CurrentLineHighlight,
 1251    gutter_hovered: bool,
 1252}
 1253
 1254#[derive(Default, Debug, Clone, Copy)]
 1255pub struct GutterDimensions {
 1256    pub left_padding: Pixels,
 1257    pub right_padding: Pixels,
 1258    pub width: Pixels,
 1259    pub margin: Pixels,
 1260    pub git_blame_entries_width: Option<Pixels>,
 1261}
 1262
 1263impl GutterDimensions {
 1264    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1265        Self {
 1266            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1267            ..Default::default()
 1268        }
 1269    }
 1270
 1271    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1272        -cx.text_system().descent(font_id, font_size)
 1273    }
 1274    /// The full width of the space taken up by the gutter.
 1275    pub fn full_width(&self) -> Pixels {
 1276        self.margin + self.width
 1277    }
 1278
 1279    /// The width of the space reserved for the fold indicators,
 1280    /// use alongside 'justify_end' and `gutter_width` to
 1281    /// right align content with the line numbers
 1282    pub fn fold_area_width(&self) -> Pixels {
 1283        self.margin + self.right_padding
 1284    }
 1285}
 1286
 1287struct CharacterDimensions {
 1288    em_width: Pixels,
 1289    em_advance: Pixels,
 1290    line_height: Pixels,
 1291}
 1292
 1293#[derive(Debug)]
 1294pub struct RemoteSelection {
 1295    pub replica_id: ReplicaId,
 1296    pub selection: Selection<Anchor>,
 1297    pub cursor_shape: CursorShape,
 1298    pub collaborator_id: CollaboratorId,
 1299    pub line_mode: bool,
 1300    pub user_name: Option<SharedString>,
 1301    pub color: PlayerColor,
 1302}
 1303
 1304#[derive(Clone, Debug)]
 1305struct SelectionHistoryEntry {
 1306    selections: Arc<[Selection<Anchor>]>,
 1307    select_next_state: Option<SelectNextState>,
 1308    select_prev_state: Option<SelectNextState>,
 1309    add_selections_state: Option<AddSelectionsState>,
 1310}
 1311
 1312#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1313enum SelectionHistoryMode {
 1314    #[default]
 1315    Normal,
 1316    Undoing,
 1317    Redoing,
 1318    Skipping,
 1319}
 1320
 1321#[derive(Clone, PartialEq, Eq, Hash)]
 1322struct HoveredCursor {
 1323    replica_id: ReplicaId,
 1324    selection_id: usize,
 1325}
 1326
 1327#[derive(Debug)]
 1328/// SelectionEffects controls the side-effects of updating the selection.
 1329///
 1330/// The default behaviour does "what you mostly want":
 1331/// - it pushes to the nav history if the cursor moved by >10 lines
 1332/// - it re-triggers completion requests
 1333/// - it scrolls to fit
 1334///
 1335/// You might want to modify these behaviours. For example when doing a "jump"
 1336/// like go to definition, we always want to add to nav history; but when scrolling
 1337/// in vim mode we never do.
 1338///
 1339/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1340/// move.
 1341#[derive(Clone)]
 1342pub struct SelectionEffects {
 1343    nav_history: Option<bool>,
 1344    completions: bool,
 1345    scroll: Option<Autoscroll>,
 1346}
 1347
 1348impl Default for SelectionEffects {
 1349    fn default() -> Self {
 1350        Self {
 1351            nav_history: None,
 1352            completions: true,
 1353            scroll: Some(Autoscroll::fit()),
 1354        }
 1355    }
 1356}
 1357impl SelectionEffects {
 1358    pub fn scroll(scroll: Autoscroll) -> Self {
 1359        Self {
 1360            scroll: Some(scroll),
 1361            ..Default::default()
 1362        }
 1363    }
 1364
 1365    pub fn no_scroll() -> Self {
 1366        Self {
 1367            scroll: None,
 1368            ..Default::default()
 1369        }
 1370    }
 1371
 1372    pub fn completions(self, completions: bool) -> Self {
 1373        Self {
 1374            completions,
 1375            ..self
 1376        }
 1377    }
 1378
 1379    pub fn nav_history(self, nav_history: bool) -> Self {
 1380        Self {
 1381            nav_history: Some(nav_history),
 1382            ..self
 1383        }
 1384    }
 1385}
 1386
 1387struct DeferredSelectionEffectsState {
 1388    changed: bool,
 1389    effects: SelectionEffects,
 1390    old_cursor_position: Anchor,
 1391    history_entry: SelectionHistoryEntry,
 1392}
 1393
 1394#[derive(Default)]
 1395struct SelectionHistory {
 1396    #[allow(clippy::type_complexity)]
 1397    selections_by_transaction:
 1398        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1399    mode: SelectionHistoryMode,
 1400    undo_stack: VecDeque<SelectionHistoryEntry>,
 1401    redo_stack: VecDeque<SelectionHistoryEntry>,
 1402}
 1403
 1404impl SelectionHistory {
 1405    #[track_caller]
 1406    fn insert_transaction(
 1407        &mut self,
 1408        transaction_id: TransactionId,
 1409        selections: Arc<[Selection<Anchor>]>,
 1410    ) {
 1411        if selections.is_empty() {
 1412            log::error!(
 1413                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1414                std::panic::Location::caller()
 1415            );
 1416            return;
 1417        }
 1418        self.selections_by_transaction
 1419            .insert(transaction_id, (selections, None));
 1420    }
 1421
 1422    #[allow(clippy::type_complexity)]
 1423    fn transaction(
 1424        &self,
 1425        transaction_id: TransactionId,
 1426    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1427        self.selections_by_transaction.get(&transaction_id)
 1428    }
 1429
 1430    #[allow(clippy::type_complexity)]
 1431    fn transaction_mut(
 1432        &mut self,
 1433        transaction_id: TransactionId,
 1434    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1435        self.selections_by_transaction.get_mut(&transaction_id)
 1436    }
 1437
 1438    fn push(&mut self, entry: SelectionHistoryEntry) {
 1439        if !entry.selections.is_empty() {
 1440            match self.mode {
 1441                SelectionHistoryMode::Normal => {
 1442                    self.push_undo(entry);
 1443                    self.redo_stack.clear();
 1444                }
 1445                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1446                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1447                SelectionHistoryMode::Skipping => {}
 1448            }
 1449        }
 1450    }
 1451
 1452    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1453        if self
 1454            .undo_stack
 1455            .back()
 1456            .is_none_or(|e| e.selections != entry.selections)
 1457        {
 1458            self.undo_stack.push_back(entry);
 1459            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1460                self.undo_stack.pop_front();
 1461            }
 1462        }
 1463    }
 1464
 1465    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1466        if self
 1467            .redo_stack
 1468            .back()
 1469            .is_none_or(|e| e.selections != entry.selections)
 1470        {
 1471            self.redo_stack.push_back(entry);
 1472            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1473                self.redo_stack.pop_front();
 1474            }
 1475        }
 1476    }
 1477}
 1478
 1479#[derive(Clone, Copy)]
 1480pub struct RowHighlightOptions {
 1481    pub autoscroll: bool,
 1482    pub include_gutter: bool,
 1483}
 1484
 1485impl Default for RowHighlightOptions {
 1486    fn default() -> Self {
 1487        Self {
 1488            autoscroll: Default::default(),
 1489            include_gutter: true,
 1490        }
 1491    }
 1492}
 1493
 1494struct RowHighlight {
 1495    index: usize,
 1496    range: Range<Anchor>,
 1497    color: Hsla,
 1498    options: RowHighlightOptions,
 1499    type_id: TypeId,
 1500}
 1501
 1502#[derive(Clone, Debug)]
 1503struct AddSelectionsState {
 1504    groups: Vec<AddSelectionsGroup>,
 1505}
 1506
 1507#[derive(Clone, Debug)]
 1508struct AddSelectionsGroup {
 1509    above: bool,
 1510    stack: Vec<usize>,
 1511}
 1512
 1513#[derive(Clone)]
 1514struct SelectNextState {
 1515    query: AhoCorasick,
 1516    wordwise: bool,
 1517    done: bool,
 1518}
 1519
 1520impl std::fmt::Debug for SelectNextState {
 1521    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1522        f.debug_struct(std::any::type_name::<Self>())
 1523            .field("wordwise", &self.wordwise)
 1524            .field("done", &self.done)
 1525            .finish()
 1526    }
 1527}
 1528
 1529#[derive(Debug)]
 1530struct AutocloseRegion {
 1531    selection_id: usize,
 1532    range: Range<Anchor>,
 1533    pair: BracketPair,
 1534}
 1535
 1536#[derive(Debug)]
 1537struct SnippetState {
 1538    ranges: Vec<Vec<Range<Anchor>>>,
 1539    active_index: usize,
 1540    choices: Vec<Option<Vec<String>>>,
 1541}
 1542
 1543#[doc(hidden)]
 1544pub struct RenameState {
 1545    pub range: Range<Anchor>,
 1546    pub old_name: Arc<str>,
 1547    pub editor: Entity<Editor>,
 1548    block_id: CustomBlockId,
 1549}
 1550
 1551struct InvalidationStack<T>(Vec<T>);
 1552
 1553struct RegisteredEditPredictionProvider {
 1554    provider: Arc<dyn EditPredictionProviderHandle>,
 1555    _subscription: Subscription,
 1556}
 1557
 1558#[derive(Debug, PartialEq, Eq)]
 1559pub struct ActiveDiagnosticGroup {
 1560    pub active_range: Range<Anchor>,
 1561    pub active_message: String,
 1562    pub group_id: usize,
 1563    pub blocks: HashSet<CustomBlockId>,
 1564}
 1565
 1566#[derive(Debug, PartialEq, Eq)]
 1567
 1568pub(crate) enum ActiveDiagnostic {
 1569    None,
 1570    All,
 1571    Group(ActiveDiagnosticGroup),
 1572}
 1573
 1574#[derive(Serialize, Deserialize, Clone, Debug)]
 1575pub struct ClipboardSelection {
 1576    /// The number of bytes in this selection.
 1577    pub len: usize,
 1578    /// Whether this was a full-line selection.
 1579    pub is_entire_line: bool,
 1580    /// The indentation of the first line when this content was originally copied.
 1581    pub first_line_indent: u32,
 1582}
 1583
 1584// selections, scroll behavior, was newest selection reversed
 1585type SelectSyntaxNodeHistoryState = (
 1586    Box<[Selection<MultiBufferOffset>]>,
 1587    SelectSyntaxNodeScrollBehavior,
 1588    bool,
 1589);
 1590
 1591#[derive(Default)]
 1592struct SelectSyntaxNodeHistory {
 1593    stack: Vec<SelectSyntaxNodeHistoryState>,
 1594    // disable temporarily to allow changing selections without losing the stack
 1595    pub disable_clearing: bool,
 1596}
 1597
 1598impl SelectSyntaxNodeHistory {
 1599    pub fn try_clear(&mut self) {
 1600        if !self.disable_clearing {
 1601            self.stack.clear();
 1602        }
 1603    }
 1604
 1605    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1606        self.stack.push(selection);
 1607    }
 1608
 1609    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1610        self.stack.pop()
 1611    }
 1612}
 1613
 1614enum SelectSyntaxNodeScrollBehavior {
 1615    CursorTop,
 1616    FitSelection,
 1617    CursorBottom,
 1618}
 1619
 1620#[derive(Debug)]
 1621pub(crate) struct NavigationData {
 1622    cursor_anchor: Anchor,
 1623    cursor_position: Point,
 1624    scroll_anchor: ScrollAnchor,
 1625    scroll_top_row: u32,
 1626}
 1627
 1628#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1629pub enum GotoDefinitionKind {
 1630    Symbol,
 1631    Declaration,
 1632    Type,
 1633    Implementation,
 1634}
 1635
 1636pub enum FormatTarget {
 1637    Buffers(HashSet<Entity<Buffer>>),
 1638    Ranges(Vec<Range<MultiBufferPoint>>),
 1639}
 1640
 1641pub(crate) struct FocusedBlock {
 1642    id: BlockId,
 1643    focus_handle: WeakFocusHandle,
 1644}
 1645
 1646#[derive(Clone, Debug)]
 1647enum JumpData {
 1648    MultiBufferRow {
 1649        row: MultiBufferRow,
 1650        line_offset_from_top: u32,
 1651    },
 1652    MultiBufferPoint {
 1653        excerpt_id: ExcerptId,
 1654        position: Point,
 1655        anchor: text::Anchor,
 1656        line_offset_from_top: u32,
 1657    },
 1658}
 1659
 1660pub enum MultibufferSelectionMode {
 1661    First,
 1662    All,
 1663}
 1664
 1665#[derive(Clone, Copy, Debug, Default)]
 1666pub struct RewrapOptions {
 1667    pub override_language_settings: bool,
 1668    pub preserve_existing_whitespace: bool,
 1669}
 1670
 1671impl Editor {
 1672    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1673        let buffer = cx.new(|cx| Buffer::local("", cx));
 1674        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1675        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1676    }
 1677
 1678    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1679        let buffer = cx.new(|cx| Buffer::local("", cx));
 1680        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1681        Self::new(EditorMode::full(), buffer, None, window, cx)
 1682    }
 1683
 1684    pub fn auto_height(
 1685        min_lines: usize,
 1686        max_lines: usize,
 1687        window: &mut Window,
 1688        cx: &mut Context<Self>,
 1689    ) -> Self {
 1690        let buffer = cx.new(|cx| Buffer::local("", cx));
 1691        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1692        Self::new(
 1693            EditorMode::AutoHeight {
 1694                min_lines,
 1695                max_lines: Some(max_lines),
 1696            },
 1697            buffer,
 1698            None,
 1699            window,
 1700            cx,
 1701        )
 1702    }
 1703
 1704    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1705    /// The editor grows as tall as needed to fit its content.
 1706    pub fn auto_height_unbounded(
 1707        min_lines: usize,
 1708        window: &mut Window,
 1709        cx: &mut Context<Self>,
 1710    ) -> Self {
 1711        let buffer = cx.new(|cx| Buffer::local("", cx));
 1712        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1713        Self::new(
 1714            EditorMode::AutoHeight {
 1715                min_lines,
 1716                max_lines: None,
 1717            },
 1718            buffer,
 1719            None,
 1720            window,
 1721            cx,
 1722        )
 1723    }
 1724
 1725    pub fn for_buffer(
 1726        buffer: Entity<Buffer>,
 1727        project: Option<Entity<Project>>,
 1728        window: &mut Window,
 1729        cx: &mut Context<Self>,
 1730    ) -> Self {
 1731        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1732        Self::new(EditorMode::full(), buffer, project, window, cx)
 1733    }
 1734
 1735    pub fn for_multibuffer(
 1736        buffer: Entity<MultiBuffer>,
 1737        project: Option<Entity<Project>>,
 1738        window: &mut Window,
 1739        cx: &mut Context<Self>,
 1740    ) -> Self {
 1741        Self::new(EditorMode::full(), buffer, project, window, cx)
 1742    }
 1743
 1744    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1745        let mut clone = Self::new(
 1746            self.mode.clone(),
 1747            self.buffer.clone(),
 1748            self.project.clone(),
 1749            window,
 1750            cx,
 1751        );
 1752        self.display_map.update(cx, |display_map, cx| {
 1753            let snapshot = display_map.snapshot(cx);
 1754            clone.display_map.update(cx, |display_map, cx| {
 1755                display_map.set_state(&snapshot, cx);
 1756            });
 1757        });
 1758        clone.folds_did_change(cx);
 1759        clone.selections.clone_state(&self.selections);
 1760        clone.scroll_manager.clone_state(&self.scroll_manager);
 1761        clone.searchable = self.searchable;
 1762        clone.read_only = self.read_only;
 1763        clone
 1764    }
 1765
 1766    pub fn new(
 1767        mode: EditorMode,
 1768        buffer: Entity<MultiBuffer>,
 1769        project: Option<Entity<Project>>,
 1770        window: &mut Window,
 1771        cx: &mut Context<Self>,
 1772    ) -> Self {
 1773        Editor::new_internal(mode, buffer, project, None, window, cx)
 1774    }
 1775
 1776    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1777        let multi_buffer = self.buffer().read(cx);
 1778        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1779        let multi_buffer_visible_start = self
 1780            .scroll_manager
 1781            .anchor()
 1782            .anchor
 1783            .to_point(&multi_buffer_snapshot);
 1784        let max_row = multi_buffer_snapshot.max_point().row;
 1785
 1786        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1787        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1788
 1789        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1790            let outline_items = buffer
 1791                .outline_items_containing(
 1792                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1793                    true,
 1794                    self.style().map(|style| style.syntax.as_ref()),
 1795                )
 1796                .into_iter()
 1797                .map(|outline_item| OutlineItem {
 1798                    depth: outline_item.depth,
 1799                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1800                    source_range_for_text: Anchor::range_in_buffer(
 1801                        *excerpt_id,
 1802                        outline_item.source_range_for_text,
 1803                    ),
 1804                    text: outline_item.text,
 1805                    highlight_ranges: outline_item.highlight_ranges,
 1806                    name_ranges: outline_item.name_ranges,
 1807                    body_range: outline_item
 1808                        .body_range
 1809                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1810                    annotation_range: outline_item
 1811                        .annotation_range
 1812                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1813                });
 1814            return Some(outline_items.collect());
 1815        }
 1816
 1817        None
 1818    }
 1819
 1820    fn new_internal(
 1821        mode: EditorMode,
 1822        multi_buffer: Entity<MultiBuffer>,
 1823        project: Option<Entity<Project>>,
 1824        display_map: Option<Entity<DisplayMap>>,
 1825        window: &mut Window,
 1826        cx: &mut Context<Self>,
 1827    ) -> Self {
 1828        debug_assert!(
 1829            display_map.is_none() || mode.is_minimap(),
 1830            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1831        );
 1832
 1833        let full_mode = mode.is_full();
 1834        let is_minimap = mode.is_minimap();
 1835        let diagnostics_max_severity = if full_mode {
 1836            EditorSettings::get_global(cx)
 1837                .diagnostics_max_severity
 1838                .unwrap_or(DiagnosticSeverity::Hint)
 1839        } else {
 1840            DiagnosticSeverity::Off
 1841        };
 1842        let style = window.text_style();
 1843        let font_size = style.font_size.to_pixels(window.rem_size());
 1844        let editor = cx.entity().downgrade();
 1845        let fold_placeholder = FoldPlaceholder {
 1846            constrain_width: false,
 1847            render: Arc::new(move |fold_id, fold_range, cx| {
 1848                let editor = editor.clone();
 1849                div()
 1850                    .id(fold_id)
 1851                    .bg(cx.theme().colors().ghost_element_background)
 1852                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1853                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1854                    .rounded_xs()
 1855                    .size_full()
 1856                    .cursor_pointer()
 1857                    .child("")
 1858                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1859                    .on_click(move |_, _window, cx| {
 1860                        editor
 1861                            .update(cx, |editor, cx| {
 1862                                editor.unfold_ranges(
 1863                                    &[fold_range.start..fold_range.end],
 1864                                    true,
 1865                                    false,
 1866                                    cx,
 1867                                );
 1868                                cx.stop_propagation();
 1869                            })
 1870                            .ok();
 1871                    })
 1872                    .into_any()
 1873            }),
 1874            merge_adjacent: true,
 1875            ..FoldPlaceholder::default()
 1876        };
 1877        let display_map = display_map.unwrap_or_else(|| {
 1878            cx.new(|cx| {
 1879                DisplayMap::new(
 1880                    multi_buffer.clone(),
 1881                    style.font(),
 1882                    font_size,
 1883                    None,
 1884                    FILE_HEADER_HEIGHT,
 1885                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1886                    fold_placeholder,
 1887                    diagnostics_max_severity,
 1888                    cx,
 1889                )
 1890            })
 1891        });
 1892
 1893        let selections = SelectionsCollection::new();
 1894
 1895        let blink_manager = cx.new(|cx| {
 1896            let mut blink_manager = BlinkManager::new(
 1897                CURSOR_BLINK_INTERVAL,
 1898                |cx| EditorSettings::get_global(cx).cursor_blink,
 1899                cx,
 1900            );
 1901            if is_minimap {
 1902                blink_manager.disable(cx);
 1903            }
 1904            blink_manager
 1905        });
 1906
 1907        let soft_wrap_mode_override =
 1908            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1909
 1910        let mut project_subscriptions = Vec::new();
 1911        if full_mode && let Some(project) = project.as_ref() {
 1912            project_subscriptions.push(cx.subscribe_in(
 1913                project,
 1914                window,
 1915                |editor, _, event, window, cx| match event {
 1916                    project::Event::RefreshCodeLens => {
 1917                        // we always query lens with actions, without storing them, always refreshing them
 1918                    }
 1919                    project::Event::RefreshInlayHints {
 1920                        server_id,
 1921                        request_id,
 1922                    } => {
 1923                        editor.refresh_inlay_hints(
 1924                            InlayHintRefreshReason::RefreshRequested {
 1925                                server_id: *server_id,
 1926                                request_id: *request_id,
 1927                            },
 1928                            cx,
 1929                        );
 1930                    }
 1931                    project::Event::LanguageServerRemoved(..) => {
 1932                        if editor.tasks_update_task.is_none() {
 1933                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1934                        }
 1935                        editor.registered_buffers.clear();
 1936                        editor.register_visible_buffers(cx);
 1937                    }
 1938                    project::Event::LanguageServerAdded(..) => {
 1939                        if editor.tasks_update_task.is_none() {
 1940                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1941                        }
 1942                    }
 1943                    project::Event::SnippetEdit(id, snippet_edits) => {
 1944                        // todo(lw): Non singletons
 1945                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 1946                            let snapshot = buffer.read(cx).snapshot();
 1947                            let focus_handle = editor.focus_handle(cx);
 1948                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 1949                                for (range, snippet) in snippet_edits {
 1950                                    let buffer_range =
 1951                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1952                                    editor
 1953                                        .insert_snippet(
 1954                                            &[MultiBufferOffset(buffer_range.start)
 1955                                                ..MultiBufferOffset(buffer_range.end)],
 1956                                            snippet.clone(),
 1957                                            window,
 1958                                            cx,
 1959                                        )
 1960                                        .ok();
 1961                                }
 1962                            }
 1963                        }
 1964                    }
 1965                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1966                        let buffer_id = *buffer_id;
 1967                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1968                            editor.register_buffer(buffer_id, cx);
 1969                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1970                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1971                            refresh_linked_ranges(editor, window, cx);
 1972                            editor.refresh_code_actions(window, cx);
 1973                            editor.refresh_document_highlights(cx);
 1974                        }
 1975                    }
 1976
 1977                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1978                        let Some(workspace) = editor.workspace() else {
 1979                            return;
 1980                        };
 1981                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1982                        else {
 1983                            return;
 1984                        };
 1985
 1986                        if active_editor.entity_id() == cx.entity_id() {
 1987                            let entity_id = cx.entity_id();
 1988                            workspace.update(cx, |this, cx| {
 1989                                this.panes_mut()
 1990                                    .iter_mut()
 1991                                    .filter(|pane| pane.entity_id() != entity_id)
 1992                                    .for_each(|p| {
 1993                                        p.update(cx, |pane, _| {
 1994                                            pane.nav_history_mut().rename_item(
 1995                                                entity_id,
 1996                                                project_path.clone(),
 1997                                                abs_path.clone().into(),
 1998                                            );
 1999                                        })
 2000                                    });
 2001                            });
 2002                            let edited_buffers_already_open = {
 2003                                let other_editors: Vec<Entity<Editor>> = workspace
 2004                                    .read(cx)
 2005                                    .panes()
 2006                                    .iter()
 2007                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 2008                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2009                                    .collect();
 2010
 2011                                transaction.0.keys().all(|buffer| {
 2012                                    other_editors.iter().any(|editor| {
 2013                                        let multi_buffer = editor.read(cx).buffer();
 2014                                        multi_buffer.read(cx).is_singleton()
 2015                                            && multi_buffer.read(cx).as_singleton().map_or(
 2016                                                false,
 2017                                                |singleton| {
 2018                                                    singleton.entity_id() == buffer.entity_id()
 2019                                                },
 2020                                            )
 2021                                    })
 2022                                })
 2023                            };
 2024                            if !edited_buffers_already_open {
 2025                                let workspace = workspace.downgrade();
 2026                                let transaction = transaction.clone();
 2027                                cx.defer_in(window, move |_, window, cx| {
 2028                                    cx.spawn_in(window, async move |editor, cx| {
 2029                                        Self::open_project_transaction(
 2030                                            &editor,
 2031                                            workspace,
 2032                                            transaction,
 2033                                            "Rename".to_string(),
 2034                                            cx,
 2035                                        )
 2036                                        .await
 2037                                        .ok()
 2038                                    })
 2039                                    .detach();
 2040                                });
 2041                            }
 2042                        }
 2043                    }
 2044
 2045                    _ => {}
 2046                },
 2047            ));
 2048            if let Some(task_inventory) = project
 2049                .read(cx)
 2050                .task_store()
 2051                .read(cx)
 2052                .task_inventory()
 2053                .cloned()
 2054            {
 2055                project_subscriptions.push(cx.observe_in(
 2056                    &task_inventory,
 2057                    window,
 2058                    |editor, _, window, cx| {
 2059                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2060                    },
 2061                ));
 2062            };
 2063
 2064            project_subscriptions.push(cx.subscribe_in(
 2065                &project.read(cx).breakpoint_store(),
 2066                window,
 2067                |editor, _, event, window, cx| match event {
 2068                    BreakpointStoreEvent::ClearDebugLines => {
 2069                        editor.clear_row_highlights::<ActiveDebugLine>();
 2070                        editor.refresh_inline_values(cx);
 2071                    }
 2072                    BreakpointStoreEvent::SetDebugLine => {
 2073                        if editor.go_to_active_debug_line(window, cx) {
 2074                            cx.stop_propagation();
 2075                        }
 2076
 2077                        editor.refresh_inline_values(cx);
 2078                    }
 2079                    _ => {}
 2080                },
 2081            ));
 2082            let git_store = project.read(cx).git_store().clone();
 2083            let project = project.clone();
 2084            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2085                if let GitStoreEvent::RepositoryAdded = event {
 2086                    this.load_diff_task = Some(
 2087                        update_uncommitted_diff_for_buffer(
 2088                            cx.entity(),
 2089                            &project,
 2090                            this.buffer.read(cx).all_buffers(),
 2091                            this.buffer.clone(),
 2092                            cx,
 2093                        )
 2094                        .shared(),
 2095                    );
 2096                }
 2097            }));
 2098        }
 2099
 2100        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2101
 2102        let inlay_hint_settings =
 2103            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2104        let focus_handle = cx.focus_handle();
 2105        if !is_minimap {
 2106            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2107                .detach();
 2108            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2109                .detach();
 2110            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2111                .detach();
 2112            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2113                .detach();
 2114            cx.observe_pending_input(window, Self::observe_pending_input)
 2115                .detach();
 2116        }
 2117
 2118        let show_indent_guides =
 2119            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2120                Some(false)
 2121            } else {
 2122                None
 2123            };
 2124
 2125        let breakpoint_store = match (&mode, project.as_ref()) {
 2126            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2127            _ => None,
 2128        };
 2129
 2130        let mut code_action_providers = Vec::new();
 2131        let mut load_uncommitted_diff = None;
 2132        if let Some(project) = project.clone() {
 2133            load_uncommitted_diff = Some(
 2134                update_uncommitted_diff_for_buffer(
 2135                    cx.entity(),
 2136                    &project,
 2137                    multi_buffer.read(cx).all_buffers(),
 2138                    multi_buffer.clone(),
 2139                    cx,
 2140                )
 2141                .shared(),
 2142            );
 2143            code_action_providers.push(Rc::new(project) as Rc<_>);
 2144        }
 2145
 2146        let mut editor = Self {
 2147            focus_handle,
 2148            show_cursor_when_unfocused: false,
 2149            last_focused_descendant: None,
 2150            buffer: multi_buffer.clone(),
 2151            display_map: display_map.clone(),
 2152            placeholder_display_map: None,
 2153            selections,
 2154            scroll_manager: ScrollManager::new(cx),
 2155            columnar_selection_state: None,
 2156            add_selections_state: None,
 2157            select_next_state: None,
 2158            select_prev_state: None,
 2159            selection_history: SelectionHistory::default(),
 2160            defer_selection_effects: false,
 2161            deferred_selection_effects_state: None,
 2162            autoclose_regions: Vec::new(),
 2163            snippet_stack: InvalidationStack::default(),
 2164            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2165            ime_transaction: None,
 2166            active_diagnostics: ActiveDiagnostic::None,
 2167            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2168            inline_diagnostics_update: Task::ready(()),
 2169            inline_diagnostics: Vec::new(),
 2170            soft_wrap_mode_override,
 2171            diagnostics_max_severity,
 2172            hard_wrap: None,
 2173            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2174            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2175            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2176            project,
 2177            blink_manager: blink_manager.clone(),
 2178            show_local_selections: true,
 2179            show_scrollbars: ScrollbarAxes {
 2180                horizontal: full_mode,
 2181                vertical: full_mode,
 2182            },
 2183            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2184            offset_content: !matches!(mode, EditorMode::SingleLine),
 2185            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2186            show_gutter: full_mode,
 2187            show_line_numbers: (!full_mode).then_some(false),
 2188            use_relative_line_numbers: None,
 2189            disable_expand_excerpt_buttons: !full_mode,
 2190            show_git_diff_gutter: None,
 2191            show_code_actions: None,
 2192            show_runnables: None,
 2193            show_breakpoints: None,
 2194            show_wrap_guides: None,
 2195            show_indent_guides,
 2196            highlight_order: 0,
 2197            highlighted_rows: HashMap::default(),
 2198            background_highlights: HashMap::default(),
 2199            gutter_highlights: HashMap::default(),
 2200            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2201            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2202            nav_history: None,
 2203            context_menu: RefCell::new(None),
 2204            context_menu_options: None,
 2205            mouse_context_menu: None,
 2206            completion_tasks: Vec::new(),
 2207            inline_blame_popover: None,
 2208            inline_blame_popover_show_task: None,
 2209            signature_help_state: SignatureHelpState::default(),
 2210            auto_signature_help: None,
 2211            find_all_references_task_sources: Vec::new(),
 2212            next_completion_id: 0,
 2213            next_inlay_id: 0,
 2214            code_action_providers,
 2215            available_code_actions: None,
 2216            code_actions_task: None,
 2217            quick_selection_highlight_task: None,
 2218            debounced_selection_highlight_task: None,
 2219            document_highlights_task: None,
 2220            linked_editing_range_task: None,
 2221            pending_rename: None,
 2222            searchable: !is_minimap,
 2223            cursor_shape: EditorSettings::get_global(cx)
 2224                .cursor_shape
 2225                .unwrap_or_default(),
 2226            current_line_highlight: None,
 2227            autoindent_mode: Some(AutoindentMode::EachLine),
 2228            collapse_matches: false,
 2229            workspace: None,
 2230            input_enabled: !is_minimap,
 2231            use_modal_editing: full_mode,
 2232            read_only: is_minimap,
 2233            use_autoclose: true,
 2234            use_auto_surround: true,
 2235            auto_replace_emoji_shortcode: false,
 2236            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2237            leader_id: None,
 2238            remote_id: None,
 2239            hover_state: HoverState::default(),
 2240            pending_mouse_down: None,
 2241            hovered_link_state: None,
 2242            edit_prediction_provider: None,
 2243            active_edit_prediction: None,
 2244            stale_edit_prediction_in_menu: None,
 2245            edit_prediction_preview: EditPredictionPreview::Inactive {
 2246                released_too_fast: false,
 2247            },
 2248            inline_diagnostics_enabled: full_mode,
 2249            diagnostics_enabled: full_mode,
 2250            word_completions_enabled: full_mode,
 2251            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2252            gutter_hovered: false,
 2253            pixel_position_of_newest_cursor: None,
 2254            last_bounds: None,
 2255            last_position_map: None,
 2256            expect_bounds_change: None,
 2257            gutter_dimensions: GutterDimensions::default(),
 2258            style: None,
 2259            show_cursor_names: false,
 2260            hovered_cursors: HashMap::default(),
 2261            next_editor_action_id: EditorActionId::default(),
 2262            editor_actions: Rc::default(),
 2263            edit_predictions_hidden_for_vim_mode: false,
 2264            show_edit_predictions_override: None,
 2265            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2266            edit_prediction_settings: EditPredictionSettings::Disabled,
 2267            edit_prediction_indent_conflict: false,
 2268            edit_prediction_requires_modifier_in_indent_conflict: true,
 2269            custom_context_menu: None,
 2270            show_git_blame_gutter: false,
 2271            show_git_blame_inline: false,
 2272            show_selection_menu: None,
 2273            show_git_blame_inline_delay_task: None,
 2274            git_blame_inline_enabled: full_mode
 2275                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2276            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2277            buffer_serialization: is_minimap.not().then(|| {
 2278                BufferSerialization::new(
 2279                    ProjectSettings::get_global(cx)
 2280                        .session
 2281                        .restore_unsaved_buffers,
 2282                )
 2283            }),
 2284            blame: None,
 2285            blame_subscription: None,
 2286            tasks: BTreeMap::default(),
 2287
 2288            breakpoint_store,
 2289            gutter_breakpoint_indicator: (None, None),
 2290            hovered_diff_hunk_row: None,
 2291            _subscriptions: (!is_minimap)
 2292                .then(|| {
 2293                    vec![
 2294                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2295                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2296                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2297                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2298                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2299                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2300                        cx.observe_window_activation(window, |editor, window, cx| {
 2301                            let active = window.is_window_active();
 2302                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2303                                if active {
 2304                                    blink_manager.enable(cx);
 2305                                } else {
 2306                                    blink_manager.disable(cx);
 2307                                }
 2308                            });
 2309                            if active {
 2310                                editor.show_mouse_cursor(cx);
 2311                            }
 2312                        }),
 2313                    ]
 2314                })
 2315                .unwrap_or_default(),
 2316            tasks_update_task: None,
 2317            pull_diagnostics_task: Task::ready(()),
 2318            colors: None,
 2319            refresh_colors_task: Task::ready(()),
 2320            inlay_hints: None,
 2321            next_color_inlay_id: 0,
 2322            post_scroll_update: Task::ready(()),
 2323            linked_edit_ranges: Default::default(),
 2324            in_project_search: false,
 2325            previous_search_ranges: None,
 2326            breadcrumb_header: None,
 2327            focused_block: None,
 2328            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2329            addons: HashMap::default(),
 2330            registered_buffers: HashMap::default(),
 2331            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2332            selection_mark_mode: false,
 2333            toggle_fold_multiple_buffers: Task::ready(()),
 2334            serialize_selections: Task::ready(()),
 2335            serialize_folds: Task::ready(()),
 2336            text_style_refinement: None,
 2337            load_diff_task: load_uncommitted_diff,
 2338            temporary_diff_override: false,
 2339            mouse_cursor_hidden: false,
 2340            minimap: None,
 2341            hide_mouse_mode: EditorSettings::get_global(cx)
 2342                .hide_mouse
 2343                .unwrap_or_default(),
 2344            change_list: ChangeList::new(),
 2345            mode,
 2346            selection_drag_state: SelectionDragState::None,
 2347            folding_newlines: Task::ready(()),
 2348            lookup_key: None,
 2349            select_next_is_case_sensitive: None,
 2350            applicable_language_settings: HashMap::default(),
 2351            accent_overrides: Vec::new(),
 2352            fetched_tree_sitter_chunks: HashMap::default(),
 2353        };
 2354
 2355        if is_minimap {
 2356            return editor;
 2357        }
 2358
 2359        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2360        editor.accent_overrides = editor.fetch_accent_overrides(cx);
 2361
 2362        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2363            editor
 2364                ._subscriptions
 2365                .push(cx.observe(breakpoints, |_, _, cx| {
 2366                    cx.notify();
 2367                }));
 2368        }
 2369        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2370        editor._subscriptions.extend(project_subscriptions);
 2371
 2372        editor._subscriptions.push(cx.subscribe_in(
 2373            &cx.entity(),
 2374            window,
 2375            |editor, _, e: &EditorEvent, window, cx| match e {
 2376                EditorEvent::ScrollPositionChanged { local, .. } => {
 2377                    if *local {
 2378                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2379                        editor.inline_blame_popover.take();
 2380                        let new_anchor = editor.scroll_manager.anchor();
 2381                        let snapshot = editor.snapshot(window, cx);
 2382                        editor.update_restoration_data(cx, move |data| {
 2383                            data.scroll_position = (
 2384                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2385                                new_anchor.offset,
 2386                            );
 2387                        });
 2388
 2389                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2390                            cx.background_executor()
 2391                                .timer(Duration::from_millis(50))
 2392                                .await;
 2393                            editor
 2394                                .update_in(cx, |editor, window, cx| {
 2395                                    editor.register_visible_buffers(cx);
 2396                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2397                                    editor.refresh_inlay_hints(
 2398                                        InlayHintRefreshReason::NewLinesShown,
 2399                                        cx,
 2400                                    );
 2401                                    editor.colorize_brackets(false, cx);
 2402                                })
 2403                                .ok();
 2404                        });
 2405                    }
 2406                }
 2407                EditorEvent::Edited { .. } => {
 2408                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2409                        .map(|vim_mode| vim_mode.0)
 2410                        .unwrap_or(false);
 2411                    if !vim_mode {
 2412                        let display_map = editor.display_snapshot(cx);
 2413                        let selections = editor.selections.all_adjusted_display(&display_map);
 2414                        let pop_state = editor
 2415                            .change_list
 2416                            .last()
 2417                            .map(|previous| {
 2418                                previous.len() == selections.len()
 2419                                    && previous.iter().enumerate().all(|(ix, p)| {
 2420                                        p.to_display_point(&display_map).row()
 2421                                            == selections[ix].head().row()
 2422                                    })
 2423                            })
 2424                            .unwrap_or(false);
 2425                        let new_positions = selections
 2426                            .into_iter()
 2427                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2428                            .collect();
 2429                        editor
 2430                            .change_list
 2431                            .push_to_change_list(pop_state, new_positions);
 2432                    }
 2433                }
 2434                _ => (),
 2435            },
 2436        ));
 2437
 2438        if let Some(dap_store) = editor
 2439            .project
 2440            .as_ref()
 2441            .map(|project| project.read(cx).dap_store())
 2442        {
 2443            let weak_editor = cx.weak_entity();
 2444
 2445            editor
 2446                ._subscriptions
 2447                .push(
 2448                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2449                        let session_entity = cx.entity();
 2450                        weak_editor
 2451                            .update(cx, |editor, cx| {
 2452                                editor._subscriptions.push(
 2453                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2454                                );
 2455                            })
 2456                            .ok();
 2457                    }),
 2458                );
 2459
 2460            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2461                editor
 2462                    ._subscriptions
 2463                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2464            }
 2465        }
 2466
 2467        // skip adding the initial selection to selection history
 2468        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2469        editor.end_selection(window, cx);
 2470        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2471
 2472        editor.scroll_manager.show_scrollbars(window, cx);
 2473        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2474
 2475        if full_mode {
 2476            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2477            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2478
 2479            if editor.git_blame_inline_enabled {
 2480                editor.start_git_blame_inline(false, window, cx);
 2481            }
 2482
 2483            editor.go_to_active_debug_line(window, cx);
 2484
 2485            editor.minimap =
 2486                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2487            editor.colors = Some(LspColorData::new(cx));
 2488            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2489
 2490            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2491                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2492            }
 2493            editor.update_lsp_data(None, window, cx);
 2494            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2495        }
 2496
 2497        editor
 2498    }
 2499
 2500    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2501        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2502    }
 2503
 2504    pub fn deploy_mouse_context_menu(
 2505        &mut self,
 2506        position: gpui::Point<Pixels>,
 2507        context_menu: Entity<ContextMenu>,
 2508        window: &mut Window,
 2509        cx: &mut Context<Self>,
 2510    ) {
 2511        self.mouse_context_menu = Some(MouseContextMenu::new(
 2512            self,
 2513            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2514            context_menu,
 2515            window,
 2516            cx,
 2517        ));
 2518    }
 2519
 2520    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2521        self.mouse_context_menu
 2522            .as_ref()
 2523            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2524    }
 2525
 2526    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2527        if self
 2528            .selections
 2529            .pending_anchor()
 2530            .is_some_and(|pending_selection| {
 2531                let snapshot = self.buffer().read(cx).snapshot(cx);
 2532                pending_selection.range().includes(range, &snapshot)
 2533            })
 2534        {
 2535            return true;
 2536        }
 2537
 2538        self.selections
 2539            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2540            .into_iter()
 2541            .any(|selection| {
 2542                // This is needed to cover a corner case, if we just check for an existing
 2543                // selection in the fold range, having a cursor at the start of the fold
 2544                // marks it as selected. Non-empty selections don't cause this.
 2545                let length = selection.end - selection.start;
 2546                length > 0
 2547            })
 2548    }
 2549
 2550    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2551        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2552    }
 2553
 2554    fn key_context_internal(
 2555        &self,
 2556        has_active_edit_prediction: bool,
 2557        window: &mut Window,
 2558        cx: &mut App,
 2559    ) -> KeyContext {
 2560        let mut key_context = KeyContext::new_with_defaults();
 2561        key_context.add("Editor");
 2562        let mode = match self.mode {
 2563            EditorMode::SingleLine => "single_line",
 2564            EditorMode::AutoHeight { .. } => "auto_height",
 2565            EditorMode::Minimap { .. } => "minimap",
 2566            EditorMode::Full { .. } => "full",
 2567        };
 2568
 2569        if EditorSettings::jupyter_enabled(cx) {
 2570            key_context.add("jupyter");
 2571        }
 2572
 2573        key_context.set("mode", mode);
 2574        if self.pending_rename.is_some() {
 2575            key_context.add("renaming");
 2576        }
 2577
 2578        if let Some(snippet_stack) = self.snippet_stack.last() {
 2579            key_context.add("in_snippet");
 2580
 2581            if snippet_stack.active_index > 0 {
 2582                key_context.add("has_previous_tabstop");
 2583            }
 2584
 2585            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2586                key_context.add("has_next_tabstop");
 2587            }
 2588        }
 2589
 2590        match self.context_menu.borrow().as_ref() {
 2591            Some(CodeContextMenu::Completions(menu)) => {
 2592                if menu.visible() {
 2593                    key_context.add("menu");
 2594                    key_context.add("showing_completions");
 2595                }
 2596            }
 2597            Some(CodeContextMenu::CodeActions(menu)) => {
 2598                if menu.visible() {
 2599                    key_context.add("menu");
 2600                    key_context.add("showing_code_actions")
 2601                }
 2602            }
 2603            None => {}
 2604        }
 2605
 2606        if self.signature_help_state.has_multiple_signatures() {
 2607            key_context.add("showing_signature_help");
 2608        }
 2609
 2610        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2611        if !self.focus_handle(cx).contains_focused(window, cx)
 2612            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2613        {
 2614            for addon in self.addons.values() {
 2615                addon.extend_key_context(&mut key_context, cx)
 2616            }
 2617        }
 2618
 2619        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2620            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2621                Some(
 2622                    file.full_path(cx)
 2623                        .extension()?
 2624                        .to_string_lossy()
 2625                        .into_owned(),
 2626                )
 2627            }) {
 2628                key_context.set("extension", extension);
 2629            }
 2630        } else {
 2631            key_context.add("multibuffer");
 2632        }
 2633
 2634        if has_active_edit_prediction {
 2635            if self.edit_prediction_in_conflict() {
 2636                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2637            } else {
 2638                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2639                key_context.add("copilot_suggestion");
 2640            }
 2641        }
 2642
 2643        if self.selection_mark_mode {
 2644            key_context.add("selection_mode");
 2645        }
 2646
 2647        let disjoint = self.selections.disjoint_anchors();
 2648        let snapshot = self.snapshot(window, cx);
 2649        let snapshot = snapshot.buffer_snapshot();
 2650        if self.mode == EditorMode::SingleLine
 2651            && let [selection] = disjoint
 2652            && selection.start == selection.end
 2653            && selection.end.to_offset(snapshot) == snapshot.len()
 2654        {
 2655            key_context.add("end_of_input");
 2656        }
 2657
 2658        if self.has_any_expanded_diff_hunks(cx) {
 2659            key_context.add("diffs_expanded");
 2660        }
 2661
 2662        key_context
 2663    }
 2664
 2665    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2666        self.last_bounds.as_ref()
 2667    }
 2668
 2669    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2670        if self.mouse_cursor_hidden {
 2671            self.mouse_cursor_hidden = false;
 2672            cx.notify();
 2673        }
 2674    }
 2675
 2676    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2677        let hide_mouse_cursor = match origin {
 2678            HideMouseCursorOrigin::TypingAction => {
 2679                matches!(
 2680                    self.hide_mouse_mode,
 2681                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2682                )
 2683            }
 2684            HideMouseCursorOrigin::MovementAction => {
 2685                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2686            }
 2687        };
 2688        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2689            self.mouse_cursor_hidden = hide_mouse_cursor;
 2690            cx.notify();
 2691        }
 2692    }
 2693
 2694    pub fn edit_prediction_in_conflict(&self) -> bool {
 2695        if !self.show_edit_predictions_in_menu() {
 2696            return false;
 2697        }
 2698
 2699        let showing_completions = self
 2700            .context_menu
 2701            .borrow()
 2702            .as_ref()
 2703            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2704
 2705        showing_completions
 2706            || self.edit_prediction_requires_modifier()
 2707            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2708            // bindings to insert tab characters.
 2709            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2710    }
 2711
 2712    pub fn accept_edit_prediction_keybind(
 2713        &self,
 2714        accept_partial: bool,
 2715        window: &mut Window,
 2716        cx: &mut App,
 2717    ) -> AcceptEditPredictionBinding {
 2718        let key_context = self.key_context_internal(true, window, cx);
 2719        let in_conflict = self.edit_prediction_in_conflict();
 2720
 2721        let bindings = if accept_partial {
 2722            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2723        } else {
 2724            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2725        };
 2726
 2727        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2728        // just the first one.
 2729        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2730            !in_conflict
 2731                || binding
 2732                    .keystrokes()
 2733                    .first()
 2734                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2735        }))
 2736    }
 2737
 2738    pub fn new_file(
 2739        workspace: &mut Workspace,
 2740        _: &workspace::NewFile,
 2741        window: &mut Window,
 2742        cx: &mut Context<Workspace>,
 2743    ) {
 2744        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2745            "Failed to create buffer",
 2746            window,
 2747            cx,
 2748            |e, _, _| match e.error_code() {
 2749                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2750                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2751                e.error_tag("required").unwrap_or("the latest version")
 2752            )),
 2753                _ => None,
 2754            },
 2755        );
 2756    }
 2757
 2758    pub fn new_in_workspace(
 2759        workspace: &mut Workspace,
 2760        window: &mut Window,
 2761        cx: &mut Context<Workspace>,
 2762    ) -> Task<Result<Entity<Editor>>> {
 2763        let project = workspace.project().clone();
 2764        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2765
 2766        cx.spawn_in(window, async move |workspace, cx| {
 2767            let buffer = create.await?;
 2768            workspace.update_in(cx, |workspace, window, cx| {
 2769                let editor =
 2770                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2771                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2772                editor
 2773            })
 2774        })
 2775    }
 2776
 2777    fn new_file_vertical(
 2778        workspace: &mut Workspace,
 2779        _: &workspace::NewFileSplitVertical,
 2780        window: &mut Window,
 2781        cx: &mut Context<Workspace>,
 2782    ) {
 2783        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2784    }
 2785
 2786    fn new_file_horizontal(
 2787        workspace: &mut Workspace,
 2788        _: &workspace::NewFileSplitHorizontal,
 2789        window: &mut Window,
 2790        cx: &mut Context<Workspace>,
 2791    ) {
 2792        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2793    }
 2794
 2795    fn new_file_split(
 2796        workspace: &mut Workspace,
 2797        action: &workspace::NewFileSplit,
 2798        window: &mut Window,
 2799        cx: &mut Context<Workspace>,
 2800    ) {
 2801        Self::new_file_in_direction(workspace, action.0, window, cx)
 2802    }
 2803
 2804    fn new_file_in_direction(
 2805        workspace: &mut Workspace,
 2806        direction: SplitDirection,
 2807        window: &mut Window,
 2808        cx: &mut Context<Workspace>,
 2809    ) {
 2810        let project = workspace.project().clone();
 2811        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2812
 2813        cx.spawn_in(window, async move |workspace, cx| {
 2814            let buffer = create.await?;
 2815            workspace.update_in(cx, move |workspace, window, cx| {
 2816                workspace.split_item(
 2817                    direction,
 2818                    Box::new(
 2819                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2820                    ),
 2821                    window,
 2822                    cx,
 2823                )
 2824            })?;
 2825            anyhow::Ok(())
 2826        })
 2827        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2828            match e.error_code() {
 2829                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2830                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2831                e.error_tag("required").unwrap_or("the latest version")
 2832            )),
 2833                _ => None,
 2834            }
 2835        });
 2836    }
 2837
 2838    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2839        self.leader_id
 2840    }
 2841
 2842    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2843        &self.buffer
 2844    }
 2845
 2846    pub fn project(&self) -> Option<&Entity<Project>> {
 2847        self.project.as_ref()
 2848    }
 2849
 2850    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2851        self.workspace.as_ref()?.0.upgrade()
 2852    }
 2853
 2854    /// Returns the workspace serialization ID if this editor should be serialized.
 2855    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2856        self.workspace
 2857            .as_ref()
 2858            .filter(|_| self.should_serialize_buffer())
 2859            .and_then(|workspace| workspace.1)
 2860    }
 2861
 2862    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2863        self.buffer().read(cx).title(cx)
 2864    }
 2865
 2866    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2867        let git_blame_gutter_max_author_length = self
 2868            .render_git_blame_gutter(cx)
 2869            .then(|| {
 2870                if let Some(blame) = self.blame.as_ref() {
 2871                    let max_author_length =
 2872                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2873                    Some(max_author_length)
 2874                } else {
 2875                    None
 2876                }
 2877            })
 2878            .flatten();
 2879
 2880        EditorSnapshot {
 2881            mode: self.mode.clone(),
 2882            show_gutter: self.show_gutter,
 2883            show_line_numbers: self.show_line_numbers,
 2884            show_git_diff_gutter: self.show_git_diff_gutter,
 2885            show_code_actions: self.show_code_actions,
 2886            show_runnables: self.show_runnables,
 2887            show_breakpoints: self.show_breakpoints,
 2888            git_blame_gutter_max_author_length,
 2889            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2890            placeholder_display_snapshot: self
 2891                .placeholder_display_map
 2892                .as_ref()
 2893                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2894            scroll_anchor: self.scroll_manager.anchor(),
 2895            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2896            is_focused: self.focus_handle.is_focused(window),
 2897            current_line_highlight: self
 2898                .current_line_highlight
 2899                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2900            gutter_hovered: self.gutter_hovered,
 2901        }
 2902    }
 2903
 2904    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2905        self.buffer.read(cx).language_at(point, cx)
 2906    }
 2907
 2908    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2909        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2910    }
 2911
 2912    pub fn active_excerpt(
 2913        &self,
 2914        cx: &App,
 2915    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2916        self.buffer
 2917            .read(cx)
 2918            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2919    }
 2920
 2921    pub fn mode(&self) -> &EditorMode {
 2922        &self.mode
 2923    }
 2924
 2925    pub fn set_mode(&mut self, mode: EditorMode) {
 2926        self.mode = mode;
 2927    }
 2928
 2929    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2930        self.collaboration_hub.as_deref()
 2931    }
 2932
 2933    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2934        self.collaboration_hub = Some(hub);
 2935    }
 2936
 2937    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2938        self.in_project_search = in_project_search;
 2939    }
 2940
 2941    pub fn set_custom_context_menu(
 2942        &mut self,
 2943        f: impl 'static
 2944        + Fn(
 2945            &mut Self,
 2946            DisplayPoint,
 2947            &mut Window,
 2948            &mut Context<Self>,
 2949        ) -> Option<Entity<ui::ContextMenu>>,
 2950    ) {
 2951        self.custom_context_menu = Some(Box::new(f))
 2952    }
 2953
 2954    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2955        self.completion_provider = provider;
 2956    }
 2957
 2958    #[cfg(any(test, feature = "test-support"))]
 2959    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2960        self.completion_provider.clone()
 2961    }
 2962
 2963    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2964        self.semantics_provider.clone()
 2965    }
 2966
 2967    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2968        self.semantics_provider = provider;
 2969    }
 2970
 2971    pub fn set_edit_prediction_provider<T>(
 2972        &mut self,
 2973        provider: Option<Entity<T>>,
 2974        window: &mut Window,
 2975        cx: &mut Context<Self>,
 2976    ) where
 2977        T: EditPredictionProvider,
 2978    {
 2979        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2980            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2981                if this.focus_handle.is_focused(window) {
 2982                    this.update_visible_edit_prediction(window, cx);
 2983                }
 2984            }),
 2985            provider: Arc::new(provider),
 2986        });
 2987        self.update_edit_prediction_settings(cx);
 2988        self.refresh_edit_prediction(false, false, window, cx);
 2989    }
 2990
 2991    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2992        self.placeholder_display_map
 2993            .as_ref()
 2994            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2995    }
 2996
 2997    pub fn set_placeholder_text(
 2998        &mut self,
 2999        placeholder_text: &str,
 3000        window: &mut Window,
 3001        cx: &mut Context<Self>,
 3002    ) {
 3003        let multibuffer = cx
 3004            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3005
 3006        let style = window.text_style();
 3007
 3008        self.placeholder_display_map = Some(cx.new(|cx| {
 3009            DisplayMap::new(
 3010                multibuffer,
 3011                style.font(),
 3012                style.font_size.to_pixels(window.rem_size()),
 3013                None,
 3014                FILE_HEADER_HEIGHT,
 3015                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3016                Default::default(),
 3017                DiagnosticSeverity::Off,
 3018                cx,
 3019            )
 3020        }));
 3021        cx.notify();
 3022    }
 3023
 3024    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3025        self.cursor_shape = cursor_shape;
 3026
 3027        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3028        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3029
 3030        cx.notify();
 3031    }
 3032
 3033    pub fn cursor_shape(&self) -> CursorShape {
 3034        self.cursor_shape
 3035    }
 3036
 3037    pub fn set_current_line_highlight(
 3038        &mut self,
 3039        current_line_highlight: Option<CurrentLineHighlight>,
 3040    ) {
 3041        self.current_line_highlight = current_line_highlight;
 3042    }
 3043
 3044    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3045        self.collapse_matches = collapse_matches;
 3046    }
 3047
 3048    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3049        if self.collapse_matches {
 3050            return range.start..range.start;
 3051        }
 3052        range.clone()
 3053    }
 3054
 3055    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3056        self.display_map.read(cx).clip_at_line_ends
 3057    }
 3058
 3059    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3060        if self.display_map.read(cx).clip_at_line_ends != clip {
 3061            self.display_map
 3062                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3063        }
 3064    }
 3065
 3066    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3067        self.input_enabled = input_enabled;
 3068    }
 3069
 3070    pub fn set_edit_predictions_hidden_for_vim_mode(
 3071        &mut self,
 3072        hidden: bool,
 3073        window: &mut Window,
 3074        cx: &mut Context<Self>,
 3075    ) {
 3076        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3077            self.edit_predictions_hidden_for_vim_mode = hidden;
 3078            if hidden {
 3079                self.update_visible_edit_prediction(window, cx);
 3080            } else {
 3081                self.refresh_edit_prediction(true, false, window, cx);
 3082            }
 3083        }
 3084    }
 3085
 3086    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3087        self.menu_edit_predictions_policy = value;
 3088    }
 3089
 3090    pub fn set_autoindent(&mut self, autoindent: bool) {
 3091        if autoindent {
 3092            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3093        } else {
 3094            self.autoindent_mode = None;
 3095        }
 3096    }
 3097
 3098    pub fn read_only(&self, cx: &App) -> bool {
 3099        self.read_only || self.buffer.read(cx).read_only()
 3100    }
 3101
 3102    pub fn set_read_only(&mut self, read_only: bool) {
 3103        self.read_only = read_only;
 3104    }
 3105
 3106    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3107        self.use_autoclose = autoclose;
 3108    }
 3109
 3110    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3111        self.use_auto_surround = auto_surround;
 3112    }
 3113
 3114    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3115        self.auto_replace_emoji_shortcode = auto_replace;
 3116    }
 3117
 3118    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3119        self.buffer_serialization = should_serialize.then(|| {
 3120            BufferSerialization::new(
 3121                ProjectSettings::get_global(cx)
 3122                    .session
 3123                    .restore_unsaved_buffers,
 3124            )
 3125        })
 3126    }
 3127
 3128    fn should_serialize_buffer(&self) -> bool {
 3129        self.buffer_serialization.is_some()
 3130    }
 3131
 3132    pub fn toggle_edit_predictions(
 3133        &mut self,
 3134        _: &ToggleEditPrediction,
 3135        window: &mut Window,
 3136        cx: &mut Context<Self>,
 3137    ) {
 3138        if self.show_edit_predictions_override.is_some() {
 3139            self.set_show_edit_predictions(None, window, cx);
 3140        } else {
 3141            let show_edit_predictions = !self.edit_predictions_enabled();
 3142            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3143        }
 3144    }
 3145
 3146    pub fn set_show_edit_predictions(
 3147        &mut self,
 3148        show_edit_predictions: Option<bool>,
 3149        window: &mut Window,
 3150        cx: &mut Context<Self>,
 3151    ) {
 3152        self.show_edit_predictions_override = show_edit_predictions;
 3153        self.update_edit_prediction_settings(cx);
 3154
 3155        if let Some(false) = show_edit_predictions {
 3156            self.discard_edit_prediction(false, cx);
 3157        } else {
 3158            self.refresh_edit_prediction(false, true, window, cx);
 3159        }
 3160    }
 3161
 3162    fn edit_predictions_disabled_in_scope(
 3163        &self,
 3164        buffer: &Entity<Buffer>,
 3165        buffer_position: language::Anchor,
 3166        cx: &App,
 3167    ) -> bool {
 3168        let snapshot = buffer.read(cx).snapshot();
 3169        let settings = snapshot.settings_at(buffer_position, cx);
 3170
 3171        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3172            return false;
 3173        };
 3174
 3175        scope.override_name().is_some_and(|scope_name| {
 3176            settings
 3177                .edit_predictions_disabled_in
 3178                .iter()
 3179                .any(|s| s == scope_name)
 3180        })
 3181    }
 3182
 3183    pub fn set_use_modal_editing(&mut self, to: bool) {
 3184        self.use_modal_editing = to;
 3185    }
 3186
 3187    pub fn use_modal_editing(&self) -> bool {
 3188        self.use_modal_editing
 3189    }
 3190
 3191    fn selections_did_change(
 3192        &mut self,
 3193        local: bool,
 3194        old_cursor_position: &Anchor,
 3195        effects: SelectionEffects,
 3196        window: &mut Window,
 3197        cx: &mut Context<Self>,
 3198    ) {
 3199        window.invalidate_character_coordinates();
 3200
 3201        // Copy selections to primary selection buffer
 3202        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3203        if local {
 3204            let selections = self
 3205                .selections
 3206                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3207            let buffer_handle = self.buffer.read(cx).read(cx);
 3208
 3209            let mut text = String::new();
 3210            for (index, selection) in selections.iter().enumerate() {
 3211                let text_for_selection = buffer_handle
 3212                    .text_for_range(selection.start..selection.end)
 3213                    .collect::<String>();
 3214
 3215                text.push_str(&text_for_selection);
 3216                if index != selections.len() - 1 {
 3217                    text.push('\n');
 3218                }
 3219            }
 3220
 3221            if !text.is_empty() {
 3222                cx.write_to_primary(ClipboardItem::new_string(text));
 3223            }
 3224        }
 3225
 3226        let selection_anchors = self.selections.disjoint_anchors_arc();
 3227
 3228        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3229            self.buffer.update(cx, |buffer, cx| {
 3230                buffer.set_active_selections(
 3231                    &selection_anchors,
 3232                    self.selections.line_mode(),
 3233                    self.cursor_shape,
 3234                    cx,
 3235                )
 3236            });
 3237        }
 3238        let display_map = self
 3239            .display_map
 3240            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3241        let buffer = display_map.buffer_snapshot();
 3242        if self.selections.count() == 1 {
 3243            self.add_selections_state = None;
 3244        }
 3245        self.select_next_state = None;
 3246        self.select_prev_state = None;
 3247        self.select_syntax_node_history.try_clear();
 3248        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3249        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3250        self.take_rename(false, window, cx);
 3251
 3252        let newest_selection = self.selections.newest_anchor();
 3253        let new_cursor_position = newest_selection.head();
 3254        let selection_start = newest_selection.start;
 3255
 3256        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3257            self.push_to_nav_history(
 3258                *old_cursor_position,
 3259                Some(new_cursor_position.to_point(buffer)),
 3260                false,
 3261                effects.nav_history == Some(true),
 3262                cx,
 3263            );
 3264        }
 3265
 3266        if local {
 3267            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3268                self.register_buffer(buffer_id, cx);
 3269            }
 3270
 3271            let mut context_menu = self.context_menu.borrow_mut();
 3272            let completion_menu = match context_menu.as_ref() {
 3273                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3274                Some(CodeContextMenu::CodeActions(_)) => {
 3275                    *context_menu = None;
 3276                    None
 3277                }
 3278                None => None,
 3279            };
 3280            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3281            drop(context_menu);
 3282
 3283            if effects.completions
 3284                && let Some(completion_position) = completion_position
 3285            {
 3286                let start_offset = selection_start.to_offset(buffer);
 3287                let position_matches = start_offset == completion_position.to_offset(buffer);
 3288                let continue_showing = if position_matches {
 3289                    if self.snippet_stack.is_empty() {
 3290                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3291                            == Some(CharKind::Word)
 3292                    } else {
 3293                        // Snippet choices can be shown even when the cursor is in whitespace.
 3294                        // Dismissing the menu with actions like backspace is handled by
 3295                        // invalidation regions.
 3296                        true
 3297                    }
 3298                } else {
 3299                    false
 3300                };
 3301
 3302                if continue_showing {
 3303                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3304                } else {
 3305                    self.hide_context_menu(window, cx);
 3306                }
 3307            }
 3308
 3309            hide_hover(self, cx);
 3310
 3311            if old_cursor_position.to_display_point(&display_map).row()
 3312                != new_cursor_position.to_display_point(&display_map).row()
 3313            {
 3314                self.available_code_actions.take();
 3315            }
 3316            self.refresh_code_actions(window, cx);
 3317            self.refresh_document_highlights(cx);
 3318            refresh_linked_ranges(self, window, cx);
 3319
 3320            self.refresh_selected_text_highlights(false, window, cx);
 3321            self.refresh_matching_bracket_highlights(window, cx);
 3322            self.update_visible_edit_prediction(window, cx);
 3323            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3324            self.inline_blame_popover.take();
 3325            if self.git_blame_inline_enabled {
 3326                self.start_inline_blame_timer(window, cx);
 3327            }
 3328        }
 3329
 3330        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3331        cx.emit(EditorEvent::SelectionsChanged { local });
 3332
 3333        let selections = &self.selections.disjoint_anchors_arc();
 3334        if selections.len() == 1 {
 3335            cx.emit(SearchEvent::ActiveMatchChanged)
 3336        }
 3337        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3338            let inmemory_selections = selections
 3339                .iter()
 3340                .map(|s| {
 3341                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3342                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3343                })
 3344                .collect();
 3345            self.update_restoration_data(cx, |data| {
 3346                data.selections = inmemory_selections;
 3347            });
 3348
 3349            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3350                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3351            {
 3352                let snapshot = self.buffer().read(cx).snapshot(cx);
 3353                let selections = selections.clone();
 3354                let background_executor = cx.background_executor().clone();
 3355                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3356                self.serialize_selections = cx.background_spawn(async move {
 3357                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3358                    let db_selections = selections
 3359                        .iter()
 3360                        .map(|selection| {
 3361                            (
 3362                                selection.start.to_offset(&snapshot).0,
 3363                                selection.end.to_offset(&snapshot).0,
 3364                            )
 3365                        })
 3366                        .collect();
 3367
 3368                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3369                        .await
 3370                        .with_context(|| {
 3371                            format!(
 3372                                "persisting editor selections for editor {editor_id}, \
 3373                                workspace {workspace_id:?}"
 3374                            )
 3375                        })
 3376                        .log_err();
 3377                });
 3378            }
 3379        }
 3380
 3381        cx.notify();
 3382    }
 3383
 3384    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3385        use text::ToOffset as _;
 3386        use text::ToPoint as _;
 3387
 3388        if self.mode.is_minimap()
 3389            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3390        {
 3391            return;
 3392        }
 3393
 3394        if !self.buffer().read(cx).is_singleton() {
 3395            return;
 3396        }
 3397
 3398        let display_snapshot = self
 3399            .display_map
 3400            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3401        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3402            return;
 3403        };
 3404        let inmemory_folds = display_snapshot
 3405            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3406            .map(|fold| {
 3407                fold.range.start.text_anchor.to_point(&snapshot)
 3408                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3409            })
 3410            .collect();
 3411        self.update_restoration_data(cx, |data| {
 3412            data.folds = inmemory_folds;
 3413        });
 3414
 3415        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3416            return;
 3417        };
 3418        let background_executor = cx.background_executor().clone();
 3419        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3420        let db_folds = display_snapshot
 3421            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3422            .map(|fold| {
 3423                (
 3424                    fold.range.start.text_anchor.to_offset(&snapshot),
 3425                    fold.range.end.text_anchor.to_offset(&snapshot),
 3426                )
 3427            })
 3428            .collect();
 3429        self.serialize_folds = cx.background_spawn(async move {
 3430            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3431            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3432                .await
 3433                .with_context(|| {
 3434                    format!(
 3435                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3436                    )
 3437                })
 3438                .log_err();
 3439        });
 3440    }
 3441
 3442    pub fn sync_selections(
 3443        &mut self,
 3444        other: Entity<Editor>,
 3445        cx: &mut Context<Self>,
 3446    ) -> gpui::Subscription {
 3447        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3448        if !other_selections.is_empty() {
 3449            self.selections
 3450                .change_with(&self.display_snapshot(cx), |selections| {
 3451                    selections.select_anchors(other_selections);
 3452                });
 3453        }
 3454
 3455        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3456            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3457                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3458                if other_selections.is_empty() {
 3459                    return;
 3460                }
 3461                let snapshot = this.display_snapshot(cx);
 3462                this.selections.change_with(&snapshot, |selections| {
 3463                    selections.select_anchors(other_selections);
 3464                });
 3465            }
 3466        });
 3467
 3468        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3469            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3470                let these_selections = this.selections.disjoint_anchors().to_vec();
 3471                if these_selections.is_empty() {
 3472                    return;
 3473                }
 3474                other.update(cx, |other_editor, cx| {
 3475                    let snapshot = other_editor.display_snapshot(cx);
 3476                    other_editor
 3477                        .selections
 3478                        .change_with(&snapshot, |selections| {
 3479                            selections.select_anchors(these_selections);
 3480                        })
 3481                });
 3482            }
 3483        });
 3484
 3485        Subscription::join(other_subscription, this_subscription)
 3486    }
 3487
 3488    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3489        if self.buffer().read(cx).is_singleton() {
 3490            return;
 3491        }
 3492        let snapshot = self.buffer.read(cx).snapshot(cx);
 3493        let buffer_ids: HashSet<BufferId> = self
 3494            .selections
 3495            .disjoint_anchor_ranges()
 3496            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3497            .collect();
 3498        for buffer_id in buffer_ids {
 3499            self.unfold_buffer(buffer_id, cx);
 3500        }
 3501    }
 3502
 3503    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3504    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3505    /// effects of selection change occur at the end of the transaction.
 3506    pub fn change_selections<R>(
 3507        &mut self,
 3508        effects: SelectionEffects,
 3509        window: &mut Window,
 3510        cx: &mut Context<Self>,
 3511        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3512    ) -> R {
 3513        let snapshot = self.display_snapshot(cx);
 3514        if let Some(state) = &mut self.deferred_selection_effects_state {
 3515            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3516            state.effects.completions = effects.completions;
 3517            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3518            let (changed, result) = self.selections.change_with(&snapshot, change);
 3519            state.changed |= changed;
 3520            return result;
 3521        }
 3522        let mut state = DeferredSelectionEffectsState {
 3523            changed: false,
 3524            effects,
 3525            old_cursor_position: self.selections.newest_anchor().head(),
 3526            history_entry: SelectionHistoryEntry {
 3527                selections: self.selections.disjoint_anchors_arc(),
 3528                select_next_state: self.select_next_state.clone(),
 3529                select_prev_state: self.select_prev_state.clone(),
 3530                add_selections_state: self.add_selections_state.clone(),
 3531            },
 3532        };
 3533        let (changed, result) = self.selections.change_with(&snapshot, change);
 3534        state.changed = state.changed || changed;
 3535        if self.defer_selection_effects {
 3536            self.deferred_selection_effects_state = Some(state);
 3537        } else {
 3538            self.apply_selection_effects(state, window, cx);
 3539        }
 3540        result
 3541    }
 3542
 3543    /// Defers the effects of selection change, so that the effects of multiple calls to
 3544    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3545    /// to selection history and the state of popovers based on selection position aren't
 3546    /// erroneously updated.
 3547    pub fn with_selection_effects_deferred<R>(
 3548        &mut self,
 3549        window: &mut Window,
 3550        cx: &mut Context<Self>,
 3551        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3552    ) -> R {
 3553        let already_deferred = self.defer_selection_effects;
 3554        self.defer_selection_effects = true;
 3555        let result = update(self, window, cx);
 3556        if !already_deferred {
 3557            self.defer_selection_effects = false;
 3558            if let Some(state) = self.deferred_selection_effects_state.take() {
 3559                self.apply_selection_effects(state, window, cx);
 3560            }
 3561        }
 3562        result
 3563    }
 3564
 3565    fn apply_selection_effects(
 3566        &mut self,
 3567        state: DeferredSelectionEffectsState,
 3568        window: &mut Window,
 3569        cx: &mut Context<Self>,
 3570    ) {
 3571        if state.changed {
 3572            self.selection_history.push(state.history_entry);
 3573
 3574            if let Some(autoscroll) = state.effects.scroll {
 3575                self.request_autoscroll(autoscroll, cx);
 3576            }
 3577
 3578            let old_cursor_position = &state.old_cursor_position;
 3579
 3580            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3581
 3582            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3583                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3584            }
 3585        }
 3586    }
 3587
 3588    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3589    where
 3590        I: IntoIterator<Item = (Range<S>, T)>,
 3591        S: ToOffset,
 3592        T: Into<Arc<str>>,
 3593    {
 3594        if self.read_only(cx) {
 3595            return;
 3596        }
 3597
 3598        self.buffer
 3599            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3600    }
 3601
 3602    pub fn edit_with_autoindent<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.update(cx, |buffer, cx| {
 3613            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3614        });
 3615    }
 3616
 3617    pub fn edit_with_block_indent<I, S, T>(
 3618        &mut self,
 3619        edits: I,
 3620        original_indent_columns: Vec<Option<u32>>,
 3621        cx: &mut Context<Self>,
 3622    ) where
 3623        I: IntoIterator<Item = (Range<S>, T)>,
 3624        S: ToOffset,
 3625        T: Into<Arc<str>>,
 3626    {
 3627        if self.read_only(cx) {
 3628            return;
 3629        }
 3630
 3631        self.buffer.update(cx, |buffer, cx| {
 3632            buffer.edit(
 3633                edits,
 3634                Some(AutoindentMode::Block {
 3635                    original_indent_columns,
 3636                }),
 3637                cx,
 3638            )
 3639        });
 3640    }
 3641
 3642    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3643        self.hide_context_menu(window, cx);
 3644
 3645        match phase {
 3646            SelectPhase::Begin {
 3647                position,
 3648                add,
 3649                click_count,
 3650            } => self.begin_selection(position, add, click_count, window, cx),
 3651            SelectPhase::BeginColumnar {
 3652                position,
 3653                goal_column,
 3654                reset,
 3655                mode,
 3656            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3657            SelectPhase::Extend {
 3658                position,
 3659                click_count,
 3660            } => self.extend_selection(position, click_count, window, cx),
 3661            SelectPhase::Update {
 3662                position,
 3663                goal_column,
 3664                scroll_delta,
 3665            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3666            SelectPhase::End => self.end_selection(window, cx),
 3667        }
 3668    }
 3669
 3670    fn extend_selection(
 3671        &mut self,
 3672        position: DisplayPoint,
 3673        click_count: usize,
 3674        window: &mut Window,
 3675        cx: &mut Context<Self>,
 3676    ) {
 3677        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3678        let tail = self
 3679            .selections
 3680            .newest::<MultiBufferOffset>(&display_map)
 3681            .tail();
 3682        let click_count = click_count.max(match self.selections.select_mode() {
 3683            SelectMode::Character => 1,
 3684            SelectMode::Word(_) => 2,
 3685            SelectMode::Line(_) => 3,
 3686            SelectMode::All => 4,
 3687        });
 3688        self.begin_selection(position, false, click_count, window, cx);
 3689
 3690        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3691
 3692        let current_selection = match self.selections.select_mode() {
 3693            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3694            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3695        };
 3696
 3697        let mut pending_selection = self
 3698            .selections
 3699            .pending_anchor()
 3700            .cloned()
 3701            .expect("extend_selection not called with pending selection");
 3702
 3703        if pending_selection
 3704            .start
 3705            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3706            == Ordering::Greater
 3707        {
 3708            pending_selection.start = current_selection.start;
 3709        }
 3710        if pending_selection
 3711            .end
 3712            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3713            == Ordering::Less
 3714        {
 3715            pending_selection.end = current_selection.end;
 3716            pending_selection.reversed = true;
 3717        }
 3718
 3719        let mut pending_mode = self.selections.pending_mode().unwrap();
 3720        match &mut pending_mode {
 3721            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3722            _ => {}
 3723        }
 3724
 3725        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3726            SelectionEffects::scroll(Autoscroll::fit())
 3727        } else {
 3728            SelectionEffects::no_scroll()
 3729        };
 3730
 3731        self.change_selections(effects, window, cx, |s| {
 3732            s.set_pending(pending_selection.clone(), pending_mode);
 3733            s.set_is_extending(true);
 3734        });
 3735    }
 3736
 3737    fn begin_selection(
 3738        &mut self,
 3739        position: DisplayPoint,
 3740        add: bool,
 3741        click_count: usize,
 3742        window: &mut Window,
 3743        cx: &mut Context<Self>,
 3744    ) {
 3745        if !self.focus_handle.is_focused(window) {
 3746            self.last_focused_descendant = None;
 3747            window.focus(&self.focus_handle);
 3748        }
 3749
 3750        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3751        let buffer = display_map.buffer_snapshot();
 3752        let position = display_map.clip_point(position, Bias::Left);
 3753
 3754        let start;
 3755        let end;
 3756        let mode;
 3757        let mut auto_scroll;
 3758        match click_count {
 3759            1 => {
 3760                start = buffer.anchor_before(position.to_point(&display_map));
 3761                end = start;
 3762                mode = SelectMode::Character;
 3763                auto_scroll = true;
 3764            }
 3765            2 => {
 3766                let position = display_map
 3767                    .clip_point(position, Bias::Left)
 3768                    .to_offset(&display_map, Bias::Left);
 3769                let (range, _) = buffer.surrounding_word(position, None);
 3770                start = buffer.anchor_before(range.start);
 3771                end = buffer.anchor_before(range.end);
 3772                mode = SelectMode::Word(start..end);
 3773                auto_scroll = true;
 3774            }
 3775            3 => {
 3776                let position = display_map
 3777                    .clip_point(position, Bias::Left)
 3778                    .to_point(&display_map);
 3779                let line_start = display_map.prev_line_boundary(position).0;
 3780                let next_line_start = buffer.clip_point(
 3781                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3782                    Bias::Left,
 3783                );
 3784                start = buffer.anchor_before(line_start);
 3785                end = buffer.anchor_before(next_line_start);
 3786                mode = SelectMode::Line(start..end);
 3787                auto_scroll = true;
 3788            }
 3789            _ => {
 3790                start = buffer.anchor_before(MultiBufferOffset(0));
 3791                end = buffer.anchor_before(buffer.len());
 3792                mode = SelectMode::All;
 3793                auto_scroll = false;
 3794            }
 3795        }
 3796        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3797
 3798        let point_to_delete: Option<usize> = {
 3799            let selected_points: Vec<Selection<Point>> =
 3800                self.selections.disjoint_in_range(start..end, &display_map);
 3801
 3802            if !add || click_count > 1 {
 3803                None
 3804            } else if !selected_points.is_empty() {
 3805                Some(selected_points[0].id)
 3806            } else {
 3807                let clicked_point_already_selected =
 3808                    self.selections.disjoint_anchors().iter().find(|selection| {
 3809                        selection.start.to_point(buffer) == start.to_point(buffer)
 3810                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3811                    });
 3812
 3813                clicked_point_already_selected.map(|selection| selection.id)
 3814            }
 3815        };
 3816
 3817        let selections_count = self.selections.count();
 3818        let effects = if auto_scroll {
 3819            SelectionEffects::default()
 3820        } else {
 3821            SelectionEffects::no_scroll()
 3822        };
 3823
 3824        self.change_selections(effects, window, cx, |s| {
 3825            if let Some(point_to_delete) = point_to_delete {
 3826                s.delete(point_to_delete);
 3827
 3828                if selections_count == 1 {
 3829                    s.set_pending_anchor_range(start..end, mode);
 3830                }
 3831            } else {
 3832                if !add {
 3833                    s.clear_disjoint();
 3834                }
 3835
 3836                s.set_pending_anchor_range(start..end, mode);
 3837            }
 3838        });
 3839    }
 3840
 3841    fn begin_columnar_selection(
 3842        &mut self,
 3843        position: DisplayPoint,
 3844        goal_column: u32,
 3845        reset: bool,
 3846        mode: ColumnarMode,
 3847        window: &mut Window,
 3848        cx: &mut Context<Self>,
 3849    ) {
 3850        if !self.focus_handle.is_focused(window) {
 3851            self.last_focused_descendant = None;
 3852            window.focus(&self.focus_handle);
 3853        }
 3854
 3855        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3856
 3857        if reset {
 3858            let pointer_position = display_map
 3859                .buffer_snapshot()
 3860                .anchor_before(position.to_point(&display_map));
 3861
 3862            self.change_selections(
 3863                SelectionEffects::scroll(Autoscroll::newest()),
 3864                window,
 3865                cx,
 3866                |s| {
 3867                    s.clear_disjoint();
 3868                    s.set_pending_anchor_range(
 3869                        pointer_position..pointer_position,
 3870                        SelectMode::Character,
 3871                    );
 3872                },
 3873            );
 3874        };
 3875
 3876        let tail = self.selections.newest::<Point>(&display_map).tail();
 3877        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3878        self.columnar_selection_state = match mode {
 3879            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3880                selection_tail: selection_anchor,
 3881                display_point: if reset {
 3882                    if position.column() != goal_column {
 3883                        Some(DisplayPoint::new(position.row(), goal_column))
 3884                    } else {
 3885                        None
 3886                    }
 3887                } else {
 3888                    None
 3889                },
 3890            }),
 3891            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3892                selection_tail: selection_anchor,
 3893            }),
 3894        };
 3895
 3896        if !reset {
 3897            self.select_columns(position, goal_column, &display_map, window, cx);
 3898        }
 3899    }
 3900
 3901    fn update_selection(
 3902        &mut self,
 3903        position: DisplayPoint,
 3904        goal_column: u32,
 3905        scroll_delta: gpui::Point<f32>,
 3906        window: &mut Window,
 3907        cx: &mut Context<Self>,
 3908    ) {
 3909        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3910
 3911        if self.columnar_selection_state.is_some() {
 3912            self.select_columns(position, goal_column, &display_map, window, cx);
 3913        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3914            let buffer = display_map.buffer_snapshot();
 3915            let head;
 3916            let tail;
 3917            let mode = self.selections.pending_mode().unwrap();
 3918            match &mode {
 3919                SelectMode::Character => {
 3920                    head = position.to_point(&display_map);
 3921                    tail = pending.tail().to_point(buffer);
 3922                }
 3923                SelectMode::Word(original_range) => {
 3924                    let offset = display_map
 3925                        .clip_point(position, Bias::Left)
 3926                        .to_offset(&display_map, Bias::Left);
 3927                    let original_range = original_range.to_offset(buffer);
 3928
 3929                    let head_offset = if buffer.is_inside_word(offset, None)
 3930                        || original_range.contains(&offset)
 3931                    {
 3932                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3933                        if word_range.start < original_range.start {
 3934                            word_range.start
 3935                        } else {
 3936                            word_range.end
 3937                        }
 3938                    } else {
 3939                        offset
 3940                    };
 3941
 3942                    head = head_offset.to_point(buffer);
 3943                    if head_offset <= original_range.start {
 3944                        tail = original_range.end.to_point(buffer);
 3945                    } else {
 3946                        tail = original_range.start.to_point(buffer);
 3947                    }
 3948                }
 3949                SelectMode::Line(original_range) => {
 3950                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3951
 3952                    let position = display_map
 3953                        .clip_point(position, Bias::Left)
 3954                        .to_point(&display_map);
 3955                    let line_start = display_map.prev_line_boundary(position).0;
 3956                    let next_line_start = buffer.clip_point(
 3957                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3958                        Bias::Left,
 3959                    );
 3960
 3961                    if line_start < original_range.start {
 3962                        head = line_start
 3963                    } else {
 3964                        head = next_line_start
 3965                    }
 3966
 3967                    if head <= original_range.start {
 3968                        tail = original_range.end;
 3969                    } else {
 3970                        tail = original_range.start;
 3971                    }
 3972                }
 3973                SelectMode::All => {
 3974                    return;
 3975                }
 3976            };
 3977
 3978            if head < tail {
 3979                pending.start = buffer.anchor_before(head);
 3980                pending.end = buffer.anchor_before(tail);
 3981                pending.reversed = true;
 3982            } else {
 3983                pending.start = buffer.anchor_before(tail);
 3984                pending.end = buffer.anchor_before(head);
 3985                pending.reversed = false;
 3986            }
 3987
 3988            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3989                s.set_pending(pending.clone(), mode);
 3990            });
 3991        } else {
 3992            log::error!("update_selection dispatched with no pending selection");
 3993            return;
 3994        }
 3995
 3996        self.apply_scroll_delta(scroll_delta, window, cx);
 3997        cx.notify();
 3998    }
 3999
 4000    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4001        self.columnar_selection_state.take();
 4002        if let Some(pending_mode) = self.selections.pending_mode() {
 4003            let selections = self
 4004                .selections
 4005                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4006            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4007                s.select(selections);
 4008                s.clear_pending();
 4009                if s.is_extending() {
 4010                    s.set_is_extending(false);
 4011                } else {
 4012                    s.set_select_mode(pending_mode);
 4013                }
 4014            });
 4015        }
 4016    }
 4017
 4018    fn select_columns(
 4019        &mut self,
 4020        head: DisplayPoint,
 4021        goal_column: u32,
 4022        display_map: &DisplaySnapshot,
 4023        window: &mut Window,
 4024        cx: &mut Context<Self>,
 4025    ) {
 4026        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4027            return;
 4028        };
 4029
 4030        let tail = match columnar_state {
 4031            ColumnarSelectionState::FromMouse {
 4032                selection_tail,
 4033                display_point,
 4034            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4035            ColumnarSelectionState::FromSelection { selection_tail } => {
 4036                selection_tail.to_display_point(display_map)
 4037            }
 4038        };
 4039
 4040        let start_row = cmp::min(tail.row(), head.row());
 4041        let end_row = cmp::max(tail.row(), head.row());
 4042        let start_column = cmp::min(tail.column(), goal_column);
 4043        let end_column = cmp::max(tail.column(), goal_column);
 4044        let reversed = start_column < tail.column();
 4045
 4046        let selection_ranges = (start_row.0..=end_row.0)
 4047            .map(DisplayRow)
 4048            .filter_map(|row| {
 4049                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4050                    || start_column <= display_map.line_len(row))
 4051                    && !display_map.is_block_line(row)
 4052                {
 4053                    let start = display_map
 4054                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4055                        .to_point(display_map);
 4056                    let end = display_map
 4057                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4058                        .to_point(display_map);
 4059                    if reversed {
 4060                        Some(end..start)
 4061                    } else {
 4062                        Some(start..end)
 4063                    }
 4064                } else {
 4065                    None
 4066                }
 4067            })
 4068            .collect::<Vec<_>>();
 4069        if selection_ranges.is_empty() {
 4070            return;
 4071        }
 4072
 4073        let ranges = match columnar_state {
 4074            ColumnarSelectionState::FromMouse { .. } => {
 4075                let mut non_empty_ranges = selection_ranges
 4076                    .iter()
 4077                    .filter(|selection_range| selection_range.start != selection_range.end)
 4078                    .peekable();
 4079                if non_empty_ranges.peek().is_some() {
 4080                    non_empty_ranges.cloned().collect()
 4081                } else {
 4082                    selection_ranges
 4083                }
 4084            }
 4085            _ => selection_ranges,
 4086        };
 4087
 4088        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4089            s.select_ranges(ranges);
 4090        });
 4091        cx.notify();
 4092    }
 4093
 4094    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4095        self.selections
 4096            .all_adjusted(snapshot)
 4097            .iter()
 4098            .any(|selection| !selection.is_empty())
 4099    }
 4100
 4101    pub fn has_pending_nonempty_selection(&self) -> bool {
 4102        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4103            Some(Selection { start, end, .. }) => start != end,
 4104            None => false,
 4105        };
 4106
 4107        pending_nonempty_selection
 4108            || (self.columnar_selection_state.is_some()
 4109                && self.selections.disjoint_anchors().len() > 1)
 4110    }
 4111
 4112    pub fn has_pending_selection(&self) -> bool {
 4113        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4114    }
 4115
 4116    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4117        self.selection_mark_mode = false;
 4118        self.selection_drag_state = SelectionDragState::None;
 4119
 4120        if self.dismiss_menus_and_popups(true, window, cx) {
 4121            cx.notify();
 4122            return;
 4123        }
 4124        if self.clear_expanded_diff_hunks(cx) {
 4125            cx.notify();
 4126            return;
 4127        }
 4128        if self.show_git_blame_gutter {
 4129            self.show_git_blame_gutter = false;
 4130            cx.notify();
 4131            return;
 4132        }
 4133
 4134        if self.mode.is_full()
 4135            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4136        {
 4137            cx.notify();
 4138            return;
 4139        }
 4140
 4141        cx.propagate();
 4142    }
 4143
 4144    pub fn dismiss_menus_and_popups(
 4145        &mut self,
 4146        is_user_requested: bool,
 4147        window: &mut Window,
 4148        cx: &mut Context<Self>,
 4149    ) -> bool {
 4150        let mut dismissed = false;
 4151
 4152        dismissed |= self.take_rename(false, window, cx).is_some();
 4153        dismissed |= self.hide_blame_popover(true, cx);
 4154        dismissed |= hide_hover(self, cx);
 4155        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4156        dismissed |= self.hide_context_menu(window, cx).is_some();
 4157        dismissed |= self.mouse_context_menu.take().is_some();
 4158        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4159        dismissed |= self.snippet_stack.pop().is_some();
 4160
 4161        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4162            self.dismiss_diagnostics(cx);
 4163            dismissed = true;
 4164        }
 4165
 4166        dismissed
 4167    }
 4168
 4169    fn linked_editing_ranges_for(
 4170        &self,
 4171        selection: Range<text::Anchor>,
 4172        cx: &App,
 4173    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4174        if self.linked_edit_ranges.is_empty() {
 4175            return None;
 4176        }
 4177        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4178            selection.end.buffer_id.and_then(|end_buffer_id| {
 4179                if selection.start.buffer_id != Some(end_buffer_id) {
 4180                    return None;
 4181                }
 4182                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4183                let snapshot = buffer.read(cx).snapshot();
 4184                self.linked_edit_ranges
 4185                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4186                    .map(|ranges| (ranges, snapshot, buffer))
 4187            })?;
 4188        use text::ToOffset as TO;
 4189        // find offset from the start of current range to current cursor position
 4190        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4191
 4192        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4193        let start_difference = start_offset - start_byte_offset;
 4194        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4195        let end_difference = end_offset - start_byte_offset;
 4196        // Current range has associated linked ranges.
 4197        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4198        for range in linked_ranges.iter() {
 4199            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4200            let end_offset = start_offset + end_difference;
 4201            let start_offset = start_offset + start_difference;
 4202            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4203                continue;
 4204            }
 4205            if self.selections.disjoint_anchor_ranges().any(|s| {
 4206                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4207                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4208                {
 4209                    return false;
 4210                }
 4211                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4212                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4213            }) {
 4214                continue;
 4215            }
 4216            let start = buffer_snapshot.anchor_after(start_offset);
 4217            let end = buffer_snapshot.anchor_after(end_offset);
 4218            linked_edits
 4219                .entry(buffer.clone())
 4220                .or_default()
 4221                .push(start..end);
 4222        }
 4223        Some(linked_edits)
 4224    }
 4225
 4226    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4227        let text: Arc<str> = text.into();
 4228
 4229        if self.read_only(cx) {
 4230            return;
 4231        }
 4232
 4233        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4234
 4235        self.unfold_buffers_with_selections(cx);
 4236
 4237        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4238        let mut bracket_inserted = false;
 4239        let mut edits = Vec::new();
 4240        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4241        let mut new_selections = Vec::with_capacity(selections.len());
 4242        let mut new_autoclose_regions = Vec::new();
 4243        let snapshot = self.buffer.read(cx).read(cx);
 4244        let mut clear_linked_edit_ranges = false;
 4245
 4246        for (selection, autoclose_region) in
 4247            self.selections_with_autoclose_regions(selections, &snapshot)
 4248        {
 4249            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4250                // Determine if the inserted text matches the opening or closing
 4251                // bracket of any of this language's bracket pairs.
 4252                let mut bracket_pair = None;
 4253                let mut is_bracket_pair_start = false;
 4254                let mut is_bracket_pair_end = false;
 4255                if !text.is_empty() {
 4256                    let mut bracket_pair_matching_end = None;
 4257                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4258                    //  and they are removing the character that triggered IME popup.
 4259                    for (pair, enabled) in scope.brackets() {
 4260                        if !pair.close && !pair.surround {
 4261                            continue;
 4262                        }
 4263
 4264                        if enabled && pair.start.ends_with(text.as_ref()) {
 4265                            let prefix_len = pair.start.len() - text.len();
 4266                            let preceding_text_matches_prefix = prefix_len == 0
 4267                                || (selection.start.column >= (prefix_len as u32)
 4268                                    && snapshot.contains_str_at(
 4269                                        Point::new(
 4270                                            selection.start.row,
 4271                                            selection.start.column - (prefix_len as u32),
 4272                                        ),
 4273                                        &pair.start[..prefix_len],
 4274                                    ));
 4275                            if preceding_text_matches_prefix {
 4276                                bracket_pair = Some(pair.clone());
 4277                                is_bracket_pair_start = true;
 4278                                break;
 4279                            }
 4280                        }
 4281                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4282                        {
 4283                            // take first bracket pair matching end, but don't break in case a later bracket
 4284                            // pair matches start
 4285                            bracket_pair_matching_end = Some(pair.clone());
 4286                        }
 4287                    }
 4288                    if let Some(end) = bracket_pair_matching_end
 4289                        && bracket_pair.is_none()
 4290                    {
 4291                        bracket_pair = Some(end);
 4292                        is_bracket_pair_end = true;
 4293                    }
 4294                }
 4295
 4296                if let Some(bracket_pair) = bracket_pair {
 4297                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4298                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4299                    let auto_surround =
 4300                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4301                    if selection.is_empty() {
 4302                        if is_bracket_pair_start {
 4303                            // If the inserted text is a suffix of an opening bracket and the
 4304                            // selection is preceded by the rest of the opening bracket, then
 4305                            // insert the closing bracket.
 4306                            let following_text_allows_autoclose = snapshot
 4307                                .chars_at(selection.start)
 4308                                .next()
 4309                                .is_none_or(|c| scope.should_autoclose_before(c));
 4310
 4311                            let preceding_text_allows_autoclose = selection.start.column == 0
 4312                                || snapshot
 4313                                    .reversed_chars_at(selection.start)
 4314                                    .next()
 4315                                    .is_none_or(|c| {
 4316                                        bracket_pair.start != bracket_pair.end
 4317                                            || !snapshot
 4318                                                .char_classifier_at(selection.start)
 4319                                                .is_word(c)
 4320                                    });
 4321
 4322                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4323                                && bracket_pair.start.len() == 1
 4324                            {
 4325                                let target = bracket_pair.start.chars().next().unwrap();
 4326                                let current_line_count = snapshot
 4327                                    .reversed_chars_at(selection.start)
 4328                                    .take_while(|&c| c != '\n')
 4329                                    .filter(|&c| c == target)
 4330                                    .count();
 4331                                current_line_count % 2 == 1
 4332                            } else {
 4333                                false
 4334                            };
 4335
 4336                            if autoclose
 4337                                && bracket_pair.close
 4338                                && following_text_allows_autoclose
 4339                                && preceding_text_allows_autoclose
 4340                                && !is_closing_quote
 4341                            {
 4342                                let anchor = snapshot.anchor_before(selection.end);
 4343                                new_selections.push((selection.map(|_| anchor), text.len()));
 4344                                new_autoclose_regions.push((
 4345                                    anchor,
 4346                                    text.len(),
 4347                                    selection.id,
 4348                                    bracket_pair.clone(),
 4349                                ));
 4350                                edits.push((
 4351                                    selection.range(),
 4352                                    format!("{}{}", text, bracket_pair.end).into(),
 4353                                ));
 4354                                bracket_inserted = true;
 4355                                continue;
 4356                            }
 4357                        }
 4358
 4359                        if let Some(region) = autoclose_region {
 4360                            // If the selection is followed by an auto-inserted closing bracket,
 4361                            // then don't insert that closing bracket again; just move the selection
 4362                            // past the closing bracket.
 4363                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4364                                && text.as_ref() == region.pair.end.as_str()
 4365                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4366                            if should_skip {
 4367                                let anchor = snapshot.anchor_after(selection.end);
 4368                                new_selections
 4369                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4370                                continue;
 4371                            }
 4372                        }
 4373
 4374                        let always_treat_brackets_as_autoclosed = snapshot
 4375                            .language_settings_at(selection.start, cx)
 4376                            .always_treat_brackets_as_autoclosed;
 4377                        if always_treat_brackets_as_autoclosed
 4378                            && is_bracket_pair_end
 4379                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4380                        {
 4381                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4382                            // and the inserted text is a closing bracket and the selection is followed
 4383                            // by the closing bracket then move the selection past the closing bracket.
 4384                            let anchor = snapshot.anchor_after(selection.end);
 4385                            new_selections.push((selection.map(|_| anchor), text.len()));
 4386                            continue;
 4387                        }
 4388                    }
 4389                    // If an opening bracket is 1 character long and is typed while
 4390                    // text is selected, then surround that text with the bracket pair.
 4391                    else if auto_surround
 4392                        && bracket_pair.surround
 4393                        && is_bracket_pair_start
 4394                        && bracket_pair.start.chars().count() == 1
 4395                    {
 4396                        edits.push((selection.start..selection.start, text.clone()));
 4397                        edits.push((
 4398                            selection.end..selection.end,
 4399                            bracket_pair.end.as_str().into(),
 4400                        ));
 4401                        bracket_inserted = true;
 4402                        new_selections.push((
 4403                            Selection {
 4404                                id: selection.id,
 4405                                start: snapshot.anchor_after(selection.start),
 4406                                end: snapshot.anchor_before(selection.end),
 4407                                reversed: selection.reversed,
 4408                                goal: selection.goal,
 4409                            },
 4410                            0,
 4411                        ));
 4412                        continue;
 4413                    }
 4414                }
 4415            }
 4416
 4417            if self.auto_replace_emoji_shortcode
 4418                && selection.is_empty()
 4419                && text.as_ref().ends_with(':')
 4420                && let Some(possible_emoji_short_code) =
 4421                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4422                && !possible_emoji_short_code.is_empty()
 4423                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4424            {
 4425                let emoji_shortcode_start = Point::new(
 4426                    selection.start.row,
 4427                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4428                );
 4429
 4430                // Remove shortcode from buffer
 4431                edits.push((
 4432                    emoji_shortcode_start..selection.start,
 4433                    "".to_string().into(),
 4434                ));
 4435                new_selections.push((
 4436                    Selection {
 4437                        id: selection.id,
 4438                        start: snapshot.anchor_after(emoji_shortcode_start),
 4439                        end: snapshot.anchor_before(selection.start),
 4440                        reversed: selection.reversed,
 4441                        goal: selection.goal,
 4442                    },
 4443                    0,
 4444                ));
 4445
 4446                // Insert emoji
 4447                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4448                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4449                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4450
 4451                continue;
 4452            }
 4453
 4454            // If not handling any auto-close operation, then just replace the selected
 4455            // text with the given input and move the selection to the end of the
 4456            // newly inserted text.
 4457            let anchor = snapshot.anchor_after(selection.end);
 4458            if !self.linked_edit_ranges.is_empty() {
 4459                let start_anchor = snapshot.anchor_before(selection.start);
 4460
 4461                let is_word_char = text.chars().next().is_none_or(|char| {
 4462                    let classifier = snapshot
 4463                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4464                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4465                    classifier.is_word(char)
 4466                });
 4467
 4468                if is_word_char {
 4469                    if let Some(ranges) = self
 4470                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4471                    {
 4472                        for (buffer, edits) in ranges {
 4473                            linked_edits
 4474                                .entry(buffer.clone())
 4475                                .or_default()
 4476                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4477                        }
 4478                    }
 4479                } else {
 4480                    clear_linked_edit_ranges = true;
 4481                }
 4482            }
 4483
 4484            new_selections.push((selection.map(|_| anchor), 0));
 4485            edits.push((selection.start..selection.end, text.clone()));
 4486        }
 4487
 4488        drop(snapshot);
 4489
 4490        self.transact(window, cx, |this, window, cx| {
 4491            if clear_linked_edit_ranges {
 4492                this.linked_edit_ranges.clear();
 4493            }
 4494            let initial_buffer_versions =
 4495                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4496
 4497            this.buffer.update(cx, |buffer, cx| {
 4498                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4499            });
 4500            for (buffer, edits) in linked_edits {
 4501                buffer.update(cx, |buffer, cx| {
 4502                    let snapshot = buffer.snapshot();
 4503                    let edits = edits
 4504                        .into_iter()
 4505                        .map(|(range, text)| {
 4506                            use text::ToPoint as TP;
 4507                            let end_point = TP::to_point(&range.end, &snapshot);
 4508                            let start_point = TP::to_point(&range.start, &snapshot);
 4509                            (start_point..end_point, text)
 4510                        })
 4511                        .sorted_by_key(|(range, _)| range.start);
 4512                    buffer.edit(edits, None, cx);
 4513                })
 4514            }
 4515            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4516            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4517            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4518            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4519                new_anchor_selections,
 4520                &map,
 4521            )
 4522            .zip(new_selection_deltas)
 4523            .map(|(selection, delta)| Selection {
 4524                id: selection.id,
 4525                start: selection.start + delta,
 4526                end: selection.end + delta,
 4527                reversed: selection.reversed,
 4528                goal: SelectionGoal::None,
 4529            })
 4530            .collect::<Vec<_>>();
 4531
 4532            let mut i = 0;
 4533            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4534                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4535                let start = map.buffer_snapshot().anchor_before(position);
 4536                let end = map.buffer_snapshot().anchor_after(position);
 4537                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4538                    match existing_state
 4539                        .range
 4540                        .start
 4541                        .cmp(&start, map.buffer_snapshot())
 4542                    {
 4543                        Ordering::Less => i += 1,
 4544                        Ordering::Greater => break,
 4545                        Ordering::Equal => {
 4546                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4547                                Ordering::Less => i += 1,
 4548                                Ordering::Equal => break,
 4549                                Ordering::Greater => break,
 4550                            }
 4551                        }
 4552                    }
 4553                }
 4554                this.autoclose_regions.insert(
 4555                    i,
 4556                    AutocloseRegion {
 4557                        selection_id,
 4558                        range: start..end,
 4559                        pair,
 4560                    },
 4561                );
 4562            }
 4563
 4564            let had_active_edit_prediction = this.has_active_edit_prediction();
 4565            this.change_selections(
 4566                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4567                window,
 4568                cx,
 4569                |s| s.select(new_selections),
 4570            );
 4571
 4572            if !bracket_inserted
 4573                && let Some(on_type_format_task) =
 4574                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4575            {
 4576                on_type_format_task.detach_and_log_err(cx);
 4577            }
 4578
 4579            let editor_settings = EditorSettings::get_global(cx);
 4580            if bracket_inserted
 4581                && (editor_settings.auto_signature_help
 4582                    || editor_settings.show_signature_help_after_edits)
 4583            {
 4584                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4585            }
 4586
 4587            let trigger_in_words =
 4588                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4589            if this.hard_wrap.is_some() {
 4590                let latest: Range<Point> = this.selections.newest(&map).range();
 4591                if latest.is_empty()
 4592                    && this
 4593                        .buffer()
 4594                        .read(cx)
 4595                        .snapshot(cx)
 4596                        .line_len(MultiBufferRow(latest.start.row))
 4597                        == latest.start.column
 4598                {
 4599                    this.rewrap_impl(
 4600                        RewrapOptions {
 4601                            override_language_settings: true,
 4602                            preserve_existing_whitespace: true,
 4603                        },
 4604                        cx,
 4605                    )
 4606                }
 4607            }
 4608            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4609            refresh_linked_ranges(this, window, cx);
 4610            this.refresh_edit_prediction(true, false, window, cx);
 4611            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4612        });
 4613    }
 4614
 4615    fn find_possible_emoji_shortcode_at_position(
 4616        snapshot: &MultiBufferSnapshot,
 4617        position: Point,
 4618    ) -> Option<String> {
 4619        let mut chars = Vec::new();
 4620        let mut found_colon = false;
 4621        for char in snapshot.reversed_chars_at(position).take(100) {
 4622            // Found a possible emoji shortcode in the middle of the buffer
 4623            if found_colon {
 4624                if char.is_whitespace() {
 4625                    chars.reverse();
 4626                    return Some(chars.iter().collect());
 4627                }
 4628                // If the previous character is not a whitespace, we are in the middle of a word
 4629                // and we only want to complete the shortcode if the word is made up of other emojis
 4630                let mut containing_word = String::new();
 4631                for ch in snapshot
 4632                    .reversed_chars_at(position)
 4633                    .skip(chars.len() + 1)
 4634                    .take(100)
 4635                {
 4636                    if ch.is_whitespace() {
 4637                        break;
 4638                    }
 4639                    containing_word.push(ch);
 4640                }
 4641                let containing_word = containing_word.chars().rev().collect::<String>();
 4642                if util::word_consists_of_emojis(containing_word.as_str()) {
 4643                    chars.reverse();
 4644                    return Some(chars.iter().collect());
 4645                }
 4646            }
 4647
 4648            if char.is_whitespace() || !char.is_ascii() {
 4649                return None;
 4650            }
 4651            if char == ':' {
 4652                found_colon = true;
 4653            } else {
 4654                chars.push(char);
 4655            }
 4656        }
 4657        // Found a possible emoji shortcode at the beginning of the buffer
 4658        chars.reverse();
 4659        Some(chars.iter().collect())
 4660    }
 4661
 4662    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4663        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4664        self.transact(window, cx, |this, window, cx| {
 4665            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4666                let selections = this
 4667                    .selections
 4668                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4669                let multi_buffer = this.buffer.read(cx);
 4670                let buffer = multi_buffer.snapshot(cx);
 4671                selections
 4672                    .iter()
 4673                    .map(|selection| {
 4674                        let start_point = selection.start.to_point(&buffer);
 4675                        let mut existing_indent =
 4676                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4677                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4678                        let start = selection.start;
 4679                        let end = selection.end;
 4680                        let selection_is_empty = start == end;
 4681                        let language_scope = buffer.language_scope_at(start);
 4682                        let (
 4683                            comment_delimiter,
 4684                            doc_delimiter,
 4685                            insert_extra_newline,
 4686                            indent_on_newline,
 4687                            indent_on_extra_newline,
 4688                        ) = if let Some(language) = &language_scope {
 4689                            let mut insert_extra_newline =
 4690                                insert_extra_newline_brackets(&buffer, start..end, language)
 4691                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4692
 4693                            // Comment extension on newline is allowed only for cursor selections
 4694                            let comment_delimiter = maybe!({
 4695                                if !selection_is_empty {
 4696                                    return None;
 4697                                }
 4698
 4699                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4700                                    return None;
 4701                                }
 4702
 4703                                let delimiters = language.line_comment_prefixes();
 4704                                let max_len_of_delimiter =
 4705                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4706                                let (snapshot, range) =
 4707                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4708
 4709                                let num_of_whitespaces = snapshot
 4710                                    .chars_for_range(range.clone())
 4711                                    .take_while(|c| c.is_whitespace())
 4712                                    .count();
 4713                                let comment_candidate = snapshot
 4714                                    .chars_for_range(range.clone())
 4715                                    .skip(num_of_whitespaces)
 4716                                    .take(max_len_of_delimiter)
 4717                                    .collect::<String>();
 4718                                let (delimiter, trimmed_len) = delimiters
 4719                                    .iter()
 4720                                    .filter_map(|delimiter| {
 4721                                        let prefix = delimiter.trim_end();
 4722                                        if comment_candidate.starts_with(prefix) {
 4723                                            Some((delimiter, prefix.len()))
 4724                                        } else {
 4725                                            None
 4726                                        }
 4727                                    })
 4728                                    .max_by_key(|(_, len)| *len)?;
 4729
 4730                                if let Some(BlockCommentConfig {
 4731                                    start: block_start, ..
 4732                                }) = language.block_comment()
 4733                                {
 4734                                    let block_start_trimmed = block_start.trim_end();
 4735                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4736                                        let line_content = snapshot
 4737                                            .chars_for_range(range)
 4738                                            .skip(num_of_whitespaces)
 4739                                            .take(block_start_trimmed.len())
 4740                                            .collect::<String>();
 4741
 4742                                        if line_content.starts_with(block_start_trimmed) {
 4743                                            return None;
 4744                                        }
 4745                                    }
 4746                                }
 4747
 4748                                let cursor_is_placed_after_comment_marker =
 4749                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4750                                if cursor_is_placed_after_comment_marker {
 4751                                    Some(delimiter.clone())
 4752                                } else {
 4753                                    None
 4754                                }
 4755                            });
 4756
 4757                            let mut indent_on_newline = IndentSize::spaces(0);
 4758                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4759
 4760                            let doc_delimiter = maybe!({
 4761                                if !selection_is_empty {
 4762                                    return None;
 4763                                }
 4764
 4765                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4766                                    return None;
 4767                                }
 4768
 4769                                let BlockCommentConfig {
 4770                                    start: start_tag,
 4771                                    end: end_tag,
 4772                                    prefix: delimiter,
 4773                                    tab_size: len,
 4774                                } = language.documentation_comment()?;
 4775                                let is_within_block_comment = buffer
 4776                                    .language_scope_at(start_point)
 4777                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4778                                if !is_within_block_comment {
 4779                                    return None;
 4780                                }
 4781
 4782                                let (snapshot, range) =
 4783                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4784
 4785                                let num_of_whitespaces = snapshot
 4786                                    .chars_for_range(range.clone())
 4787                                    .take_while(|c| c.is_whitespace())
 4788                                    .count();
 4789
 4790                                // 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.
 4791                                let column = start_point.column;
 4792                                let cursor_is_after_start_tag = {
 4793                                    let start_tag_len = start_tag.len();
 4794                                    let start_tag_line = snapshot
 4795                                        .chars_for_range(range.clone())
 4796                                        .skip(num_of_whitespaces)
 4797                                        .take(start_tag_len)
 4798                                        .collect::<String>();
 4799                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4800                                        num_of_whitespaces + start_tag_len <= column as usize
 4801                                    } else {
 4802                                        false
 4803                                    }
 4804                                };
 4805
 4806                                let cursor_is_after_delimiter = {
 4807                                    let delimiter_trim = delimiter.trim_end();
 4808                                    let delimiter_line = snapshot
 4809                                        .chars_for_range(range.clone())
 4810                                        .skip(num_of_whitespaces)
 4811                                        .take(delimiter_trim.len())
 4812                                        .collect::<String>();
 4813                                    if delimiter_line.starts_with(delimiter_trim) {
 4814                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4815                                    } else {
 4816                                        false
 4817                                    }
 4818                                };
 4819
 4820                                let cursor_is_before_end_tag_if_exists = {
 4821                                    let mut char_position = 0u32;
 4822                                    let mut end_tag_offset = None;
 4823
 4824                                    'outer: for chunk in snapshot.text_for_range(range) {
 4825                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4826                                            let chars_before_match =
 4827                                                chunk[..byte_pos].chars().count() as u32;
 4828                                            end_tag_offset =
 4829                                                Some(char_position + chars_before_match);
 4830                                            break 'outer;
 4831                                        }
 4832                                        char_position += chunk.chars().count() as u32;
 4833                                    }
 4834
 4835                                    if let Some(end_tag_offset) = end_tag_offset {
 4836                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4837                                        if cursor_is_after_start_tag {
 4838                                            if cursor_is_before_end_tag {
 4839                                                insert_extra_newline = true;
 4840                                            }
 4841                                            let cursor_is_at_start_of_end_tag =
 4842                                                column == end_tag_offset;
 4843                                            if cursor_is_at_start_of_end_tag {
 4844                                                indent_on_extra_newline.len = *len;
 4845                                            }
 4846                                        }
 4847                                        cursor_is_before_end_tag
 4848                                    } else {
 4849                                        true
 4850                                    }
 4851                                };
 4852
 4853                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4854                                    && cursor_is_before_end_tag_if_exists
 4855                                {
 4856                                    if cursor_is_after_start_tag {
 4857                                        indent_on_newline.len = *len;
 4858                                    }
 4859                                    Some(delimiter.clone())
 4860                                } else {
 4861                                    None
 4862                                }
 4863                            });
 4864
 4865                            (
 4866                                comment_delimiter,
 4867                                doc_delimiter,
 4868                                insert_extra_newline,
 4869                                indent_on_newline,
 4870                                indent_on_extra_newline,
 4871                            )
 4872                        } else {
 4873                            (
 4874                                None,
 4875                                None,
 4876                                false,
 4877                                IndentSize::default(),
 4878                                IndentSize::default(),
 4879                            )
 4880                        };
 4881
 4882                        let prevent_auto_indent = doc_delimiter.is_some();
 4883                        let delimiter = comment_delimiter.or(doc_delimiter);
 4884
 4885                        let capacity_for_delimiter =
 4886                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4887                        let mut new_text = String::with_capacity(
 4888                            1 + capacity_for_delimiter
 4889                                + existing_indent.len as usize
 4890                                + indent_on_newline.len as usize
 4891                                + indent_on_extra_newline.len as usize,
 4892                        );
 4893                        new_text.push('\n');
 4894                        new_text.extend(existing_indent.chars());
 4895                        new_text.extend(indent_on_newline.chars());
 4896
 4897                        if let Some(delimiter) = &delimiter {
 4898                            new_text.push_str(delimiter);
 4899                        }
 4900
 4901                        if insert_extra_newline {
 4902                            new_text.push('\n');
 4903                            new_text.extend(existing_indent.chars());
 4904                            new_text.extend(indent_on_extra_newline.chars());
 4905                        }
 4906
 4907                        let anchor = buffer.anchor_after(end);
 4908                        let new_selection = selection.map(|_| anchor);
 4909                        (
 4910                            ((start..end, new_text), prevent_auto_indent),
 4911                            (insert_extra_newline, new_selection),
 4912                        )
 4913                    })
 4914                    .unzip()
 4915            };
 4916
 4917            let mut auto_indent_edits = Vec::new();
 4918            let mut edits = Vec::new();
 4919            for (edit, prevent_auto_indent) in edits_with_flags {
 4920                if prevent_auto_indent {
 4921                    edits.push(edit);
 4922                } else {
 4923                    auto_indent_edits.push(edit);
 4924                }
 4925            }
 4926            if !edits.is_empty() {
 4927                this.edit(edits, cx);
 4928            }
 4929            if !auto_indent_edits.is_empty() {
 4930                this.edit_with_autoindent(auto_indent_edits, cx);
 4931            }
 4932
 4933            let buffer = this.buffer.read(cx).snapshot(cx);
 4934            let new_selections = selection_info
 4935                .into_iter()
 4936                .map(|(extra_newline_inserted, new_selection)| {
 4937                    let mut cursor = new_selection.end.to_point(&buffer);
 4938                    if extra_newline_inserted {
 4939                        cursor.row -= 1;
 4940                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4941                    }
 4942                    new_selection.map(|_| cursor)
 4943                })
 4944                .collect();
 4945
 4946            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4947            this.refresh_edit_prediction(true, false, window, cx);
 4948        });
 4949    }
 4950
 4951    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4952        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4953
 4954        let buffer = self.buffer.read(cx);
 4955        let snapshot = buffer.snapshot(cx);
 4956
 4957        let mut edits = Vec::new();
 4958        let mut rows = Vec::new();
 4959
 4960        for (rows_inserted, selection) in self
 4961            .selections
 4962            .all_adjusted(&self.display_snapshot(cx))
 4963            .into_iter()
 4964            .enumerate()
 4965        {
 4966            let cursor = selection.head();
 4967            let row = cursor.row;
 4968
 4969            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4970
 4971            let newline = "\n".to_string();
 4972            edits.push((start_of_line..start_of_line, newline));
 4973
 4974            rows.push(row + rows_inserted as u32);
 4975        }
 4976
 4977        self.transact(window, cx, |editor, window, cx| {
 4978            editor.edit(edits, cx);
 4979
 4980            editor.change_selections(Default::default(), window, cx, |s| {
 4981                let mut index = 0;
 4982                s.move_cursors_with(|map, _, _| {
 4983                    let row = rows[index];
 4984                    index += 1;
 4985
 4986                    let point = Point::new(row, 0);
 4987                    let boundary = map.next_line_boundary(point).1;
 4988                    let clipped = map.clip_point(boundary, Bias::Left);
 4989
 4990                    (clipped, SelectionGoal::None)
 4991                });
 4992            });
 4993
 4994            let mut indent_edits = Vec::new();
 4995            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4996            for row in rows {
 4997                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4998                for (row, indent) in indents {
 4999                    if indent.len == 0 {
 5000                        continue;
 5001                    }
 5002
 5003                    let text = match indent.kind {
 5004                        IndentKind::Space => " ".repeat(indent.len as usize),
 5005                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5006                    };
 5007                    let point = Point::new(row.0, 0);
 5008                    indent_edits.push((point..point, text));
 5009                }
 5010            }
 5011            editor.edit(indent_edits, cx);
 5012        });
 5013    }
 5014
 5015    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5016        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5017
 5018        let buffer = self.buffer.read(cx);
 5019        let snapshot = buffer.snapshot(cx);
 5020
 5021        let mut edits = Vec::new();
 5022        let mut rows = Vec::new();
 5023        let mut rows_inserted = 0;
 5024
 5025        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5026            let cursor = selection.head();
 5027            let row = cursor.row;
 5028
 5029            let point = Point::new(row + 1, 0);
 5030            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5031
 5032            let newline = "\n".to_string();
 5033            edits.push((start_of_line..start_of_line, newline));
 5034
 5035            rows_inserted += 1;
 5036            rows.push(row + rows_inserted);
 5037        }
 5038
 5039        self.transact(window, cx, |editor, window, cx| {
 5040            editor.edit(edits, cx);
 5041
 5042            editor.change_selections(Default::default(), window, cx, |s| {
 5043                let mut index = 0;
 5044                s.move_cursors_with(|map, _, _| {
 5045                    let row = rows[index];
 5046                    index += 1;
 5047
 5048                    let point = Point::new(row, 0);
 5049                    let boundary = map.next_line_boundary(point).1;
 5050                    let clipped = map.clip_point(boundary, Bias::Left);
 5051
 5052                    (clipped, SelectionGoal::None)
 5053                });
 5054            });
 5055
 5056            let mut indent_edits = Vec::new();
 5057            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5058            for row in rows {
 5059                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5060                for (row, indent) in indents {
 5061                    if indent.len == 0 {
 5062                        continue;
 5063                    }
 5064
 5065                    let text = match indent.kind {
 5066                        IndentKind::Space => " ".repeat(indent.len as usize),
 5067                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5068                    };
 5069                    let point = Point::new(row.0, 0);
 5070                    indent_edits.push((point..point, text));
 5071                }
 5072            }
 5073            editor.edit(indent_edits, cx);
 5074        });
 5075    }
 5076
 5077    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5078        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5079            original_indent_columns: Vec::new(),
 5080        });
 5081        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5082    }
 5083
 5084    fn insert_with_autoindent_mode(
 5085        &mut self,
 5086        text: &str,
 5087        autoindent_mode: Option<AutoindentMode>,
 5088        window: &mut Window,
 5089        cx: &mut Context<Self>,
 5090    ) {
 5091        if self.read_only(cx) {
 5092            return;
 5093        }
 5094
 5095        let text: Arc<str> = text.into();
 5096        self.transact(window, cx, |this, window, cx| {
 5097            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5098            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5099                let anchors = {
 5100                    let snapshot = buffer.read(cx);
 5101                    old_selections
 5102                        .iter()
 5103                        .map(|s| {
 5104                            let anchor = snapshot.anchor_after(s.head());
 5105                            s.map(|_| anchor)
 5106                        })
 5107                        .collect::<Vec<_>>()
 5108                };
 5109                buffer.edit(
 5110                    old_selections
 5111                        .iter()
 5112                        .map(|s| (s.start..s.end, text.clone())),
 5113                    autoindent_mode,
 5114                    cx,
 5115                );
 5116                anchors
 5117            });
 5118
 5119            this.change_selections(Default::default(), window, cx, |s| {
 5120                s.select_anchors(selection_anchors);
 5121            });
 5122
 5123            cx.notify();
 5124        });
 5125    }
 5126
 5127    fn trigger_completion_on_input(
 5128        &mut self,
 5129        text: &str,
 5130        trigger_in_words: bool,
 5131        window: &mut Window,
 5132        cx: &mut Context<Self>,
 5133    ) {
 5134        let completions_source = self
 5135            .context_menu
 5136            .borrow()
 5137            .as_ref()
 5138            .and_then(|menu| match menu {
 5139                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5140                CodeContextMenu::CodeActions(_) => None,
 5141            });
 5142
 5143        match completions_source {
 5144            Some(CompletionsMenuSource::Words { .. }) => {
 5145                self.open_or_update_completions_menu(
 5146                    Some(CompletionsMenuSource::Words {
 5147                        ignore_threshold: false,
 5148                    }),
 5149                    None,
 5150                    trigger_in_words,
 5151                    window,
 5152                    cx,
 5153                );
 5154            }
 5155            _ => self.open_or_update_completions_menu(
 5156                None,
 5157                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5158                true,
 5159                window,
 5160                cx,
 5161            ),
 5162        }
 5163    }
 5164
 5165    /// If any empty selections is touching the start of its innermost containing autoclose
 5166    /// region, expand it to select the brackets.
 5167    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5168        let selections = self
 5169            .selections
 5170            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5171        let buffer = self.buffer.read(cx).read(cx);
 5172        let new_selections = self
 5173            .selections_with_autoclose_regions(selections, &buffer)
 5174            .map(|(mut selection, region)| {
 5175                if !selection.is_empty() {
 5176                    return selection;
 5177                }
 5178
 5179                if let Some(region) = region {
 5180                    let mut range = region.range.to_offset(&buffer);
 5181                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5182                        range.start -= region.pair.start.len();
 5183                        if buffer.contains_str_at(range.start, &region.pair.start)
 5184                            && buffer.contains_str_at(range.end, &region.pair.end)
 5185                        {
 5186                            range.end += region.pair.end.len();
 5187                            selection.start = range.start;
 5188                            selection.end = range.end;
 5189
 5190                            return selection;
 5191                        }
 5192                    }
 5193                }
 5194
 5195                let always_treat_brackets_as_autoclosed = buffer
 5196                    .language_settings_at(selection.start, cx)
 5197                    .always_treat_brackets_as_autoclosed;
 5198
 5199                if !always_treat_brackets_as_autoclosed {
 5200                    return selection;
 5201                }
 5202
 5203                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5204                    for (pair, enabled) in scope.brackets() {
 5205                        if !enabled || !pair.close {
 5206                            continue;
 5207                        }
 5208
 5209                        if buffer.contains_str_at(selection.start, &pair.end) {
 5210                            let pair_start_len = pair.start.len();
 5211                            if buffer.contains_str_at(
 5212                                selection.start.saturating_sub_usize(pair_start_len),
 5213                                &pair.start,
 5214                            ) {
 5215                                selection.start -= pair_start_len;
 5216                                selection.end += pair.end.len();
 5217
 5218                                return selection;
 5219                            }
 5220                        }
 5221                    }
 5222                }
 5223
 5224                selection
 5225            })
 5226            .collect();
 5227
 5228        drop(buffer);
 5229        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5230            selections.select(new_selections)
 5231        });
 5232    }
 5233
 5234    /// Iterate the given selections, and for each one, find the smallest surrounding
 5235    /// autoclose region. This uses the ordering of the selections and the autoclose
 5236    /// regions to avoid repeated comparisons.
 5237    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5238        &'a self,
 5239        selections: impl IntoIterator<Item = Selection<D>>,
 5240        buffer: &'a MultiBufferSnapshot,
 5241    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5242        let mut i = 0;
 5243        let mut regions = self.autoclose_regions.as_slice();
 5244        selections.into_iter().map(move |selection| {
 5245            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5246
 5247            let mut enclosing = None;
 5248            while let Some(pair_state) = regions.get(i) {
 5249                if pair_state.range.end.to_offset(buffer) < range.start {
 5250                    regions = &regions[i + 1..];
 5251                    i = 0;
 5252                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5253                    break;
 5254                } else {
 5255                    if pair_state.selection_id == selection.id {
 5256                        enclosing = Some(pair_state);
 5257                    }
 5258                    i += 1;
 5259                }
 5260            }
 5261
 5262            (selection, enclosing)
 5263        })
 5264    }
 5265
 5266    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5267    fn invalidate_autoclose_regions(
 5268        &mut self,
 5269        mut selections: &[Selection<Anchor>],
 5270        buffer: &MultiBufferSnapshot,
 5271    ) {
 5272        self.autoclose_regions.retain(|state| {
 5273            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5274                return false;
 5275            }
 5276
 5277            let mut i = 0;
 5278            while let Some(selection) = selections.get(i) {
 5279                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5280                    selections = &selections[1..];
 5281                    continue;
 5282                }
 5283                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5284                    break;
 5285                }
 5286                if selection.id == state.selection_id {
 5287                    return true;
 5288                } else {
 5289                    i += 1;
 5290                }
 5291            }
 5292            false
 5293        });
 5294    }
 5295
 5296    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5297        let offset = position.to_offset(buffer);
 5298        let (word_range, kind) =
 5299            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5300        if offset > word_range.start && kind == Some(CharKind::Word) {
 5301            Some(
 5302                buffer
 5303                    .text_for_range(word_range.start..offset)
 5304                    .collect::<String>(),
 5305            )
 5306        } else {
 5307            None
 5308        }
 5309    }
 5310
 5311    pub fn visible_excerpts(
 5312        &self,
 5313        lsp_related_only: bool,
 5314        cx: &mut Context<Editor>,
 5315    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5316        let project = self.project().cloned();
 5317        let multi_buffer = self.buffer().read(cx);
 5318        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5319        let multi_buffer_visible_start = self
 5320            .scroll_manager
 5321            .anchor()
 5322            .anchor
 5323            .to_point(&multi_buffer_snapshot);
 5324        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5325            multi_buffer_visible_start
 5326                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5327            Bias::Left,
 5328        );
 5329        multi_buffer_snapshot
 5330            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5331            .into_iter()
 5332            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5333            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5334                if !lsp_related_only {
 5335                    return Some((
 5336                        excerpt_id,
 5337                        (
 5338                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5339                            buffer.version().clone(),
 5340                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5341                        ),
 5342                    ));
 5343                }
 5344
 5345                let project = project.as_ref()?.read(cx);
 5346                let buffer_file = project::File::from_dyn(buffer.file())?;
 5347                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5348                let worktree_entry = buffer_worktree
 5349                    .read(cx)
 5350                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5351                if worktree_entry.is_ignored {
 5352                    None
 5353                } else {
 5354                    Some((
 5355                        excerpt_id,
 5356                        (
 5357                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5358                            buffer.version().clone(),
 5359                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5360                        ),
 5361                    ))
 5362                }
 5363            })
 5364            .collect()
 5365    }
 5366
 5367    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5368        TextLayoutDetails {
 5369            text_system: window.text_system().clone(),
 5370            editor_style: self.style.clone().unwrap(),
 5371            rem_size: window.rem_size(),
 5372            scroll_anchor: self.scroll_manager.anchor(),
 5373            visible_rows: self.visible_line_count(),
 5374            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5375        }
 5376    }
 5377
 5378    fn trigger_on_type_formatting(
 5379        &self,
 5380        input: String,
 5381        window: &mut Window,
 5382        cx: &mut Context<Self>,
 5383    ) -> Option<Task<Result<()>>> {
 5384        if input.len() != 1 {
 5385            return None;
 5386        }
 5387
 5388        let project = self.project()?;
 5389        let position = self.selections.newest_anchor().head();
 5390        let (buffer, buffer_position) = self
 5391            .buffer
 5392            .read(cx)
 5393            .text_anchor_for_position(position, cx)?;
 5394
 5395        let settings = language_settings::language_settings(
 5396            buffer
 5397                .read(cx)
 5398                .language_at(buffer_position)
 5399                .map(|l| l.name()),
 5400            buffer.read(cx).file(),
 5401            cx,
 5402        );
 5403        if !settings.use_on_type_format {
 5404            return None;
 5405        }
 5406
 5407        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5408        // hence we do LSP request & edit on host side only — add formats to host's history.
 5409        let push_to_lsp_host_history = true;
 5410        // If this is not the host, append its history with new edits.
 5411        let push_to_client_history = project.read(cx).is_via_collab();
 5412
 5413        let on_type_formatting = project.update(cx, |project, cx| {
 5414            project.on_type_format(
 5415                buffer.clone(),
 5416                buffer_position,
 5417                input,
 5418                push_to_lsp_host_history,
 5419                cx,
 5420            )
 5421        });
 5422        Some(cx.spawn_in(window, async move |editor, cx| {
 5423            if let Some(transaction) = on_type_formatting.await? {
 5424                if push_to_client_history {
 5425                    buffer
 5426                        .update(cx, |buffer, _| {
 5427                            buffer.push_transaction(transaction, Instant::now());
 5428                            buffer.finalize_last_transaction();
 5429                        })
 5430                        .ok();
 5431                }
 5432                editor.update(cx, |editor, cx| {
 5433                    editor.refresh_document_highlights(cx);
 5434                })?;
 5435            }
 5436            Ok(())
 5437        }))
 5438    }
 5439
 5440    pub fn show_word_completions(
 5441        &mut self,
 5442        _: &ShowWordCompletions,
 5443        window: &mut Window,
 5444        cx: &mut Context<Self>,
 5445    ) {
 5446        self.open_or_update_completions_menu(
 5447            Some(CompletionsMenuSource::Words {
 5448                ignore_threshold: true,
 5449            }),
 5450            None,
 5451            false,
 5452            window,
 5453            cx,
 5454        );
 5455    }
 5456
 5457    pub fn show_completions(
 5458        &mut self,
 5459        _: &ShowCompletions,
 5460        window: &mut Window,
 5461        cx: &mut Context<Self>,
 5462    ) {
 5463        self.open_or_update_completions_menu(None, None, false, window, cx);
 5464    }
 5465
 5466    fn open_or_update_completions_menu(
 5467        &mut self,
 5468        requested_source: Option<CompletionsMenuSource>,
 5469        trigger: Option<String>,
 5470        trigger_in_words: bool,
 5471        window: &mut Window,
 5472        cx: &mut Context<Self>,
 5473    ) {
 5474        if self.pending_rename.is_some() {
 5475            return;
 5476        }
 5477
 5478        let completions_source = self
 5479            .context_menu
 5480            .borrow()
 5481            .as_ref()
 5482            .and_then(|menu| match menu {
 5483                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5484                CodeContextMenu::CodeActions(_) => None,
 5485            });
 5486
 5487        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5488
 5489        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5490        // inserted and selected. To handle that case, the start of the selection is used so that
 5491        // the menu starts with all choices.
 5492        let position = self
 5493            .selections
 5494            .newest_anchor()
 5495            .start
 5496            .bias_right(&multibuffer_snapshot);
 5497        if position.diff_base_anchor.is_some() {
 5498            return;
 5499        }
 5500        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5501        let Some(buffer) = buffer_position
 5502            .text_anchor
 5503            .buffer_id
 5504            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5505        else {
 5506            return;
 5507        };
 5508        let buffer_snapshot = buffer.read(cx).snapshot();
 5509
 5510        let query: Option<Arc<String>> =
 5511            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5512                .map(|query| query.into());
 5513
 5514        drop(multibuffer_snapshot);
 5515
 5516        // Hide the current completions menu when query is empty. Without this, cached
 5517        // completions from before the trigger char may be reused (#32774).
 5518        if query.is_none() {
 5519            let menu_is_open = matches!(
 5520                self.context_menu.borrow().as_ref(),
 5521                Some(CodeContextMenu::Completions(_))
 5522            );
 5523            if menu_is_open {
 5524                self.hide_context_menu(window, cx);
 5525            }
 5526        }
 5527
 5528        let mut ignore_word_threshold = false;
 5529        let provider = match requested_source {
 5530            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5531            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5532                ignore_word_threshold = ignore_threshold;
 5533                None
 5534            }
 5535            Some(CompletionsMenuSource::SnippetChoices)
 5536            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5537                log::error!("bug: SnippetChoices requested_source is not handled");
 5538                None
 5539            }
 5540        };
 5541
 5542        let sort_completions = provider
 5543            .as_ref()
 5544            .is_some_and(|provider| provider.sort_completions());
 5545
 5546        let filter_completions = provider
 5547            .as_ref()
 5548            .is_none_or(|provider| provider.filter_completions());
 5549
 5550        let was_snippets_only = matches!(
 5551            completions_source,
 5552            Some(CompletionsMenuSource::SnippetsOnly)
 5553        );
 5554
 5555        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5556            if filter_completions {
 5557                menu.filter(
 5558                    query.clone().unwrap_or_default(),
 5559                    buffer_position.text_anchor,
 5560                    &buffer,
 5561                    provider.clone(),
 5562                    window,
 5563                    cx,
 5564                );
 5565            }
 5566            // When `is_incomplete` is false, no need to re-query completions when the current query
 5567            // is a suffix of the initial query.
 5568            let was_complete = !menu.is_incomplete;
 5569            if was_complete && !was_snippets_only {
 5570                // If the new query is a suffix of the old query (typing more characters) and
 5571                // the previous result was complete, the existing completions can be filtered.
 5572                //
 5573                // Note that snippet completions are always complete.
 5574                let query_matches = match (&menu.initial_query, &query) {
 5575                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5576                    (None, _) => true,
 5577                    _ => false,
 5578                };
 5579                if query_matches {
 5580                    let position_matches = if menu.initial_position == position {
 5581                        true
 5582                    } else {
 5583                        let snapshot = self.buffer.read(cx).read(cx);
 5584                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5585                    };
 5586                    if position_matches {
 5587                        return;
 5588                    }
 5589                }
 5590            }
 5591        };
 5592
 5593        let Anchor {
 5594            excerpt_id: buffer_excerpt_id,
 5595            text_anchor: buffer_position,
 5596            ..
 5597        } = buffer_position;
 5598
 5599        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5600            buffer_snapshot.surrounding_word(buffer_position, None)
 5601        {
 5602            let word_to_exclude = buffer_snapshot
 5603                .text_for_range(word_range.clone())
 5604                .collect::<String>();
 5605            (
 5606                buffer_snapshot.anchor_before(word_range.start)
 5607                    ..buffer_snapshot.anchor_after(buffer_position),
 5608                Some(word_to_exclude),
 5609            )
 5610        } else {
 5611            (buffer_position..buffer_position, None)
 5612        };
 5613
 5614        let language = buffer_snapshot
 5615            .language_at(buffer_position)
 5616            .map(|language| language.name());
 5617
 5618        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5619            .completions
 5620            .clone();
 5621
 5622        let show_completion_documentation = buffer_snapshot
 5623            .settings_at(buffer_position, cx)
 5624            .show_completion_documentation;
 5625
 5626        // The document can be large, so stay in reasonable bounds when searching for words,
 5627        // otherwise completion pop-up might be slow to appear.
 5628        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5629        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5630        let min_word_search = buffer_snapshot.clip_point(
 5631            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5632            Bias::Left,
 5633        );
 5634        let max_word_search = buffer_snapshot.clip_point(
 5635            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5636            Bias::Right,
 5637        );
 5638        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5639            ..buffer_snapshot.point_to_offset(max_word_search);
 5640
 5641        let skip_digits = query
 5642            .as_ref()
 5643            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5644
 5645        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5646            trigger.as_ref().is_none_or(|trigger| {
 5647                provider.is_completion_trigger(
 5648                    &buffer,
 5649                    position.text_anchor,
 5650                    trigger,
 5651                    trigger_in_words,
 5652                    completions_source.is_some(),
 5653                    cx,
 5654                )
 5655            })
 5656        });
 5657
 5658        let provider_responses = if let Some(provider) = &provider
 5659            && load_provider_completions
 5660        {
 5661            let trigger_character =
 5662                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5663            let completion_context = CompletionContext {
 5664                trigger_kind: match &trigger_character {
 5665                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5666                    None => CompletionTriggerKind::INVOKED,
 5667                },
 5668                trigger_character,
 5669            };
 5670
 5671            provider.completions(
 5672                buffer_excerpt_id,
 5673                &buffer,
 5674                buffer_position,
 5675                completion_context,
 5676                window,
 5677                cx,
 5678            )
 5679        } else {
 5680            Task::ready(Ok(Vec::new()))
 5681        };
 5682
 5683        let load_word_completions = if !self.word_completions_enabled {
 5684            false
 5685        } else if requested_source
 5686            == Some(CompletionsMenuSource::Words {
 5687                ignore_threshold: true,
 5688            })
 5689        {
 5690            true
 5691        } else {
 5692            load_provider_completions
 5693                && completion_settings.words != WordsCompletionMode::Disabled
 5694                && (ignore_word_threshold || {
 5695                    let words_min_length = completion_settings.words_min_length;
 5696                    // check whether word has at least `words_min_length` characters
 5697                    let query_chars = query.iter().flat_map(|q| q.chars());
 5698                    query_chars.take(words_min_length).count() == words_min_length
 5699                })
 5700        };
 5701
 5702        let mut words = if load_word_completions {
 5703            cx.background_spawn({
 5704                let buffer_snapshot = buffer_snapshot.clone();
 5705                async move {
 5706                    buffer_snapshot.words_in_range(WordsQuery {
 5707                        fuzzy_contents: None,
 5708                        range: word_search_range,
 5709                        skip_digits,
 5710                    })
 5711                }
 5712            })
 5713        } else {
 5714            Task::ready(BTreeMap::default())
 5715        };
 5716
 5717        let snippets = if let Some(provider) = &provider
 5718            && provider.show_snippets()
 5719            && let Some(project) = self.project()
 5720        {
 5721            let char_classifier = buffer_snapshot
 5722                .char_classifier_at(buffer_position)
 5723                .scope_context(Some(CharScopeContext::Completion));
 5724            project.update(cx, |project, cx| {
 5725                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5726            })
 5727        } else {
 5728            Task::ready(Ok(CompletionResponse {
 5729                completions: Vec::new(),
 5730                display_options: Default::default(),
 5731                is_incomplete: false,
 5732            }))
 5733        };
 5734
 5735        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5736
 5737        let id = post_inc(&mut self.next_completion_id);
 5738        let task = cx.spawn_in(window, async move |editor, cx| {
 5739            let Ok(()) = editor.update(cx, |this, _| {
 5740                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5741            }) else {
 5742                return;
 5743            };
 5744
 5745            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5746            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5747            let mut completions = Vec::new();
 5748            let mut is_incomplete = false;
 5749            let mut display_options: Option<CompletionDisplayOptions> = None;
 5750            if let Some(provider_responses) = provider_responses.await.log_err()
 5751                && !provider_responses.is_empty()
 5752            {
 5753                for response in provider_responses {
 5754                    completions.extend(response.completions);
 5755                    is_incomplete = is_incomplete || response.is_incomplete;
 5756                    match display_options.as_mut() {
 5757                        None => {
 5758                            display_options = Some(response.display_options);
 5759                        }
 5760                        Some(options) => options.merge(&response.display_options),
 5761                    }
 5762                }
 5763                if completion_settings.words == WordsCompletionMode::Fallback {
 5764                    words = Task::ready(BTreeMap::default());
 5765                }
 5766            }
 5767            let display_options = display_options.unwrap_or_default();
 5768
 5769            let mut words = words.await;
 5770            if let Some(word_to_exclude) = &word_to_exclude {
 5771                words.remove(word_to_exclude);
 5772            }
 5773            for lsp_completion in &completions {
 5774                words.remove(&lsp_completion.new_text);
 5775            }
 5776            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5777                replace_range: word_replace_range.clone(),
 5778                new_text: word.clone(),
 5779                label: CodeLabel::plain(word, None),
 5780                match_start: None,
 5781                snippet_deduplication_key: None,
 5782                icon_path: None,
 5783                documentation: None,
 5784                source: CompletionSource::BufferWord {
 5785                    word_range,
 5786                    resolved: false,
 5787                },
 5788                insert_text_mode: Some(InsertTextMode::AS_IS),
 5789                confirm: None,
 5790            }));
 5791
 5792            completions.extend(
 5793                snippets
 5794                    .await
 5795                    .into_iter()
 5796                    .flat_map(|response| response.completions),
 5797            );
 5798
 5799            let menu = if completions.is_empty() {
 5800                None
 5801            } else {
 5802                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5803                    let languages = editor
 5804                        .workspace
 5805                        .as_ref()
 5806                        .and_then(|(workspace, _)| workspace.upgrade())
 5807                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5808                    let menu = CompletionsMenu::new(
 5809                        id,
 5810                        requested_source.unwrap_or(if load_provider_completions {
 5811                            CompletionsMenuSource::Normal
 5812                        } else {
 5813                            CompletionsMenuSource::SnippetsOnly
 5814                        }),
 5815                        sort_completions,
 5816                        show_completion_documentation,
 5817                        position,
 5818                        query.clone(),
 5819                        is_incomplete,
 5820                        buffer.clone(),
 5821                        completions.into(),
 5822                        display_options,
 5823                        snippet_sort_order,
 5824                        languages,
 5825                        language,
 5826                        cx,
 5827                    );
 5828
 5829                    let query = if filter_completions { query } else { None };
 5830                    let matches_task = menu.do_async_filtering(
 5831                        query.unwrap_or_default(),
 5832                        buffer_position,
 5833                        &buffer,
 5834                        cx,
 5835                    );
 5836                    (menu, matches_task)
 5837                }) else {
 5838                    return;
 5839                };
 5840
 5841                let matches = matches_task.await;
 5842
 5843                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5844                    // Newer menu already set, so exit.
 5845                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5846                        editor.context_menu.borrow().as_ref()
 5847                        && prev_menu.id > id
 5848                    {
 5849                        return;
 5850                    };
 5851
 5852                    // Only valid to take prev_menu because either the new menu is immediately set
 5853                    // below, or the menu is hidden.
 5854                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5855                        editor.context_menu.borrow_mut().take()
 5856                    {
 5857                        let position_matches =
 5858                            if prev_menu.initial_position == menu.initial_position {
 5859                                true
 5860                            } else {
 5861                                let snapshot = editor.buffer.read(cx).read(cx);
 5862                                prev_menu.initial_position.to_offset(&snapshot)
 5863                                    == menu.initial_position.to_offset(&snapshot)
 5864                            };
 5865                        if position_matches {
 5866                            // Preserve markdown cache before `set_filter_results` because it will
 5867                            // try to populate the documentation cache.
 5868                            menu.preserve_markdown_cache(prev_menu);
 5869                        }
 5870                    };
 5871
 5872                    menu.set_filter_results(matches, provider, window, cx);
 5873                }) else {
 5874                    return;
 5875                };
 5876
 5877                menu.visible().then_some(menu)
 5878            };
 5879
 5880            editor
 5881                .update_in(cx, |editor, window, cx| {
 5882                    if editor.focus_handle.is_focused(window)
 5883                        && let Some(menu) = menu
 5884                    {
 5885                        *editor.context_menu.borrow_mut() =
 5886                            Some(CodeContextMenu::Completions(menu));
 5887
 5888                        crate::hover_popover::hide_hover(editor, cx);
 5889                        if editor.show_edit_predictions_in_menu() {
 5890                            editor.update_visible_edit_prediction(window, cx);
 5891                        } else {
 5892                            editor.discard_edit_prediction(false, cx);
 5893                        }
 5894
 5895                        cx.notify();
 5896                        return;
 5897                    }
 5898
 5899                    if editor.completion_tasks.len() <= 1 {
 5900                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5901                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5902                        // If it was already hidden and we don't show edit predictions in the menu,
 5903                        // we should also show the edit prediction when available.
 5904                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5905                            editor.update_visible_edit_prediction(window, cx);
 5906                        }
 5907                    }
 5908                })
 5909                .ok();
 5910        });
 5911
 5912        self.completion_tasks.push((id, task));
 5913    }
 5914
 5915    #[cfg(feature = "test-support")]
 5916    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5917        let menu = self.context_menu.borrow();
 5918        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5919            let completions = menu.completions.borrow();
 5920            Some(completions.to_vec())
 5921        } else {
 5922            None
 5923        }
 5924    }
 5925
 5926    pub fn with_completions_menu_matching_id<R>(
 5927        &self,
 5928        id: CompletionId,
 5929        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5930    ) -> R {
 5931        let mut context_menu = self.context_menu.borrow_mut();
 5932        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5933            return f(None);
 5934        };
 5935        if completions_menu.id != id {
 5936            return f(None);
 5937        }
 5938        f(Some(completions_menu))
 5939    }
 5940
 5941    pub fn confirm_completion(
 5942        &mut self,
 5943        action: &ConfirmCompletion,
 5944        window: &mut Window,
 5945        cx: &mut Context<Self>,
 5946    ) -> Option<Task<Result<()>>> {
 5947        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5948        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5949    }
 5950
 5951    pub fn confirm_completion_insert(
 5952        &mut self,
 5953        _: &ConfirmCompletionInsert,
 5954        window: &mut Window,
 5955        cx: &mut Context<Self>,
 5956    ) -> Option<Task<Result<()>>> {
 5957        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5958        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5959    }
 5960
 5961    pub fn confirm_completion_replace(
 5962        &mut self,
 5963        _: &ConfirmCompletionReplace,
 5964        window: &mut Window,
 5965        cx: &mut Context<Self>,
 5966    ) -> Option<Task<Result<()>>> {
 5967        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5968        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5969    }
 5970
 5971    pub fn compose_completion(
 5972        &mut self,
 5973        action: &ComposeCompletion,
 5974        window: &mut Window,
 5975        cx: &mut Context<Self>,
 5976    ) -> Option<Task<Result<()>>> {
 5977        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5978        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5979    }
 5980
 5981    fn do_completion(
 5982        &mut self,
 5983        item_ix: Option<usize>,
 5984        intent: CompletionIntent,
 5985        window: &mut Window,
 5986        cx: &mut Context<Editor>,
 5987    ) -> Option<Task<Result<()>>> {
 5988        use language::ToOffset as _;
 5989
 5990        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5991        else {
 5992            return None;
 5993        };
 5994
 5995        let candidate_id = {
 5996            let entries = completions_menu.entries.borrow();
 5997            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5998            if self.show_edit_predictions_in_menu() {
 5999                self.discard_edit_prediction(true, cx);
 6000            }
 6001            mat.candidate_id
 6002        };
 6003
 6004        let completion = completions_menu
 6005            .completions
 6006            .borrow()
 6007            .get(candidate_id)?
 6008            .clone();
 6009        cx.stop_propagation();
 6010
 6011        let buffer_handle = completions_menu.buffer.clone();
 6012
 6013        let CompletionEdit {
 6014            new_text,
 6015            snippet,
 6016            replace_range,
 6017        } = process_completion_for_edit(
 6018            &completion,
 6019            intent,
 6020            &buffer_handle,
 6021            &completions_menu.initial_position.text_anchor,
 6022            cx,
 6023        );
 6024
 6025        let buffer = buffer_handle.read(cx);
 6026        let snapshot = self.buffer.read(cx).snapshot(cx);
 6027        let newest_anchor = self.selections.newest_anchor();
 6028        let replace_range_multibuffer = {
 6029            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6030            excerpt.map_range_from_buffer(replace_range.clone())
 6031        };
 6032        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6033            return None;
 6034        }
 6035
 6036        let old_text = buffer
 6037            .text_for_range(replace_range.clone())
 6038            .collect::<String>();
 6039        let lookbehind = newest_anchor
 6040            .start
 6041            .text_anchor
 6042            .to_offset(buffer)
 6043            .saturating_sub(replace_range.start.0);
 6044        let lookahead = replace_range
 6045            .end
 6046            .0
 6047            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6048        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6049        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6050
 6051        let selections = self
 6052            .selections
 6053            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6054        let mut ranges = Vec::new();
 6055        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6056
 6057        for selection in &selections {
 6058            let range = if selection.id == newest_anchor.id {
 6059                replace_range_multibuffer.clone()
 6060            } else {
 6061                let mut range = selection.range();
 6062
 6063                // if prefix is present, don't duplicate it
 6064                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6065                    range.start = range.start.saturating_sub_usize(lookbehind);
 6066
 6067                    // if suffix is also present, mimic the newest cursor and replace it
 6068                    if selection.id != newest_anchor.id
 6069                        && snapshot.contains_str_at(range.end, suffix)
 6070                    {
 6071                        range.end += lookahead;
 6072                    }
 6073                }
 6074                range
 6075            };
 6076
 6077            ranges.push(range.clone());
 6078
 6079            if !self.linked_edit_ranges.is_empty() {
 6080                let start_anchor = snapshot.anchor_before(range.start);
 6081                let end_anchor = snapshot.anchor_after(range.end);
 6082                if let Some(ranges) = self
 6083                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6084                {
 6085                    for (buffer, edits) in ranges {
 6086                        linked_edits
 6087                            .entry(buffer.clone())
 6088                            .or_default()
 6089                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6090                    }
 6091                }
 6092            }
 6093        }
 6094
 6095        let common_prefix_len = old_text
 6096            .chars()
 6097            .zip(new_text.chars())
 6098            .take_while(|(a, b)| a == b)
 6099            .map(|(a, _)| a.len_utf8())
 6100            .sum::<usize>();
 6101
 6102        cx.emit(EditorEvent::InputHandled {
 6103            utf16_range_to_replace: None,
 6104            text: new_text[common_prefix_len..].into(),
 6105        });
 6106
 6107        self.transact(window, cx, |editor, window, cx| {
 6108            if let Some(mut snippet) = snippet {
 6109                snippet.text = new_text.to_string();
 6110                editor
 6111                    .insert_snippet(&ranges, snippet, window, cx)
 6112                    .log_err();
 6113            } else {
 6114                editor.buffer.update(cx, |multi_buffer, cx| {
 6115                    let auto_indent = match completion.insert_text_mode {
 6116                        Some(InsertTextMode::AS_IS) => None,
 6117                        _ => editor.autoindent_mode.clone(),
 6118                    };
 6119                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6120                    multi_buffer.edit(edits, auto_indent, cx);
 6121                });
 6122            }
 6123            for (buffer, edits) in linked_edits {
 6124                buffer.update(cx, |buffer, cx| {
 6125                    let snapshot = buffer.snapshot();
 6126                    let edits = edits
 6127                        .into_iter()
 6128                        .map(|(range, text)| {
 6129                            use text::ToPoint as TP;
 6130                            let end_point = TP::to_point(&range.end, &snapshot);
 6131                            let start_point = TP::to_point(&range.start, &snapshot);
 6132                            (start_point..end_point, text)
 6133                        })
 6134                        .sorted_by_key(|(range, _)| range.start);
 6135                    buffer.edit(edits, None, cx);
 6136                })
 6137            }
 6138
 6139            editor.refresh_edit_prediction(true, false, window, cx);
 6140        });
 6141        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6142
 6143        let show_new_completions_on_confirm = completion
 6144            .confirm
 6145            .as_ref()
 6146            .is_some_and(|confirm| confirm(intent, window, cx));
 6147        if show_new_completions_on_confirm {
 6148            self.open_or_update_completions_menu(None, None, false, window, cx);
 6149        }
 6150
 6151        let provider = self.completion_provider.as_ref()?;
 6152
 6153        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6154        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6155            let CompletionSource::Lsp {
 6156                lsp_completion,
 6157                server_id,
 6158                ..
 6159            } = &completion.source
 6160            else {
 6161                return None;
 6162            };
 6163            let lsp_command = lsp_completion.command.as_ref()?;
 6164            let available_commands = lsp_store
 6165                .read(cx)
 6166                .lsp_server_capabilities
 6167                .get(server_id)
 6168                .and_then(|server_capabilities| {
 6169                    server_capabilities
 6170                        .execute_command_provider
 6171                        .as_ref()
 6172                        .map(|options| options.commands.as_slice())
 6173                })?;
 6174            if available_commands.contains(&lsp_command.command) {
 6175                Some(CodeAction {
 6176                    server_id: *server_id,
 6177                    range: language::Anchor::MIN..language::Anchor::MIN,
 6178                    lsp_action: LspAction::Command(lsp_command.clone()),
 6179                    resolved: false,
 6180                })
 6181            } else {
 6182                None
 6183            }
 6184        });
 6185
 6186        drop(completion);
 6187        let apply_edits = provider.apply_additional_edits_for_completion(
 6188            buffer_handle.clone(),
 6189            completions_menu.completions.clone(),
 6190            candidate_id,
 6191            true,
 6192            cx,
 6193        );
 6194
 6195        let editor_settings = EditorSettings::get_global(cx);
 6196        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6197            // After the code completion is finished, users often want to know what signatures are needed.
 6198            // so we should automatically call signature_help
 6199            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6200        }
 6201
 6202        Some(cx.spawn_in(window, async move |editor, cx| {
 6203            apply_edits.await?;
 6204
 6205            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6206                let title = command.lsp_action.title().to_owned();
 6207                let project_transaction = lsp_store
 6208                    .update(cx, |lsp_store, cx| {
 6209                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6210                    })?
 6211                    .await
 6212                    .context("applying post-completion command")?;
 6213                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6214                    Self::open_project_transaction(
 6215                        &editor,
 6216                        workspace.downgrade(),
 6217                        project_transaction,
 6218                        title,
 6219                        cx,
 6220                    )
 6221                    .await?;
 6222                }
 6223            }
 6224
 6225            Ok(())
 6226        }))
 6227    }
 6228
 6229    pub fn toggle_code_actions(
 6230        &mut self,
 6231        action: &ToggleCodeActions,
 6232        window: &mut Window,
 6233        cx: &mut Context<Self>,
 6234    ) {
 6235        let quick_launch = action.quick_launch;
 6236        let mut context_menu = self.context_menu.borrow_mut();
 6237        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6238            if code_actions.deployed_from == action.deployed_from {
 6239                // Toggle if we're selecting the same one
 6240                *context_menu = None;
 6241                cx.notify();
 6242                return;
 6243            } else {
 6244                // Otherwise, clear it and start a new one
 6245                *context_menu = None;
 6246                cx.notify();
 6247            }
 6248        }
 6249        drop(context_menu);
 6250        let snapshot = self.snapshot(window, cx);
 6251        let deployed_from = action.deployed_from.clone();
 6252        let action = action.clone();
 6253        self.completion_tasks.clear();
 6254        self.discard_edit_prediction(false, cx);
 6255
 6256        let multibuffer_point = match &action.deployed_from {
 6257            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6258                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6259            }
 6260            _ => self
 6261                .selections
 6262                .newest::<Point>(&snapshot.display_snapshot)
 6263                .head(),
 6264        };
 6265        let Some((buffer, buffer_row)) = snapshot
 6266            .buffer_snapshot()
 6267            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6268            .and_then(|(buffer_snapshot, range)| {
 6269                self.buffer()
 6270                    .read(cx)
 6271                    .buffer(buffer_snapshot.remote_id())
 6272                    .map(|buffer| (buffer, range.start.row))
 6273            })
 6274        else {
 6275            return;
 6276        };
 6277        let buffer_id = buffer.read(cx).remote_id();
 6278        let tasks = self
 6279            .tasks
 6280            .get(&(buffer_id, buffer_row))
 6281            .map(|t| Arc::new(t.to_owned()));
 6282
 6283        if !self.focus_handle.is_focused(window) {
 6284            return;
 6285        }
 6286        let project = self.project.clone();
 6287
 6288        let code_actions_task = match deployed_from {
 6289            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6290            _ => self.code_actions(buffer_row, window, cx),
 6291        };
 6292
 6293        let runnable_task = match deployed_from {
 6294            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6295            _ => {
 6296                let mut task_context_task = Task::ready(None);
 6297                if let Some(tasks) = &tasks
 6298                    && let Some(project) = project
 6299                {
 6300                    task_context_task =
 6301                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6302                }
 6303
 6304                cx.spawn_in(window, {
 6305                    let buffer = buffer.clone();
 6306                    async move |editor, cx| {
 6307                        let task_context = task_context_task.await;
 6308
 6309                        let resolved_tasks =
 6310                            tasks
 6311                                .zip(task_context.clone())
 6312                                .map(|(tasks, task_context)| ResolvedTasks {
 6313                                    templates: tasks.resolve(&task_context).collect(),
 6314                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6315                                        multibuffer_point.row,
 6316                                        tasks.column,
 6317                                    )),
 6318                                });
 6319                        let debug_scenarios = editor
 6320                            .update(cx, |editor, cx| {
 6321                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6322                            })?
 6323                            .await;
 6324                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6325                    }
 6326                })
 6327            }
 6328        };
 6329
 6330        cx.spawn_in(window, async move |editor, cx| {
 6331            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6332            let code_actions = code_actions_task.await;
 6333            let spawn_straight_away = quick_launch
 6334                && resolved_tasks
 6335                    .as_ref()
 6336                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6337                && code_actions
 6338                    .as_ref()
 6339                    .is_none_or(|actions| actions.is_empty())
 6340                && debug_scenarios.is_empty();
 6341
 6342            editor.update_in(cx, |editor, window, cx| {
 6343                crate::hover_popover::hide_hover(editor, cx);
 6344                let actions = CodeActionContents::new(
 6345                    resolved_tasks,
 6346                    code_actions,
 6347                    debug_scenarios,
 6348                    task_context.unwrap_or_default(),
 6349                );
 6350
 6351                // Don't show the menu if there are no actions available
 6352                if actions.is_empty() {
 6353                    cx.notify();
 6354                    return Task::ready(Ok(()));
 6355                }
 6356
 6357                *editor.context_menu.borrow_mut() =
 6358                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6359                        buffer,
 6360                        actions,
 6361                        selected_item: Default::default(),
 6362                        scroll_handle: UniformListScrollHandle::default(),
 6363                        deployed_from,
 6364                    }));
 6365                cx.notify();
 6366                if spawn_straight_away
 6367                    && let Some(task) = editor.confirm_code_action(
 6368                        &ConfirmCodeAction { item_ix: Some(0) },
 6369                        window,
 6370                        cx,
 6371                    )
 6372                {
 6373                    return task;
 6374                }
 6375
 6376                Task::ready(Ok(()))
 6377            })
 6378        })
 6379        .detach_and_log_err(cx);
 6380    }
 6381
 6382    fn debug_scenarios(
 6383        &mut self,
 6384        resolved_tasks: &Option<ResolvedTasks>,
 6385        buffer: &Entity<Buffer>,
 6386        cx: &mut App,
 6387    ) -> Task<Vec<task::DebugScenario>> {
 6388        maybe!({
 6389            let project = self.project()?;
 6390            let dap_store = project.read(cx).dap_store();
 6391            let mut scenarios = vec![];
 6392            let resolved_tasks = resolved_tasks.as_ref()?;
 6393            let buffer = buffer.read(cx);
 6394            let language = buffer.language()?;
 6395            let file = buffer.file();
 6396            let debug_adapter = language_settings(language.name().into(), file, cx)
 6397                .debuggers
 6398                .first()
 6399                .map(SharedString::from)
 6400                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6401
 6402            dap_store.update(cx, |dap_store, cx| {
 6403                for (_, task) in &resolved_tasks.templates {
 6404                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6405                        task.original_task().clone(),
 6406                        debug_adapter.clone().into(),
 6407                        task.display_label().to_owned().into(),
 6408                        cx,
 6409                    );
 6410                    scenarios.push(maybe_scenario);
 6411                }
 6412            });
 6413            Some(cx.background_spawn(async move {
 6414                futures::future::join_all(scenarios)
 6415                    .await
 6416                    .into_iter()
 6417                    .flatten()
 6418                    .collect::<Vec<_>>()
 6419            }))
 6420        })
 6421        .unwrap_or_else(|| Task::ready(vec![]))
 6422    }
 6423
 6424    fn code_actions(
 6425        &mut self,
 6426        buffer_row: u32,
 6427        window: &mut Window,
 6428        cx: &mut Context<Self>,
 6429    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6430        let mut task = self.code_actions_task.take();
 6431        cx.spawn_in(window, async move |editor, cx| {
 6432            while let Some(prev_task) = task {
 6433                prev_task.await.log_err();
 6434                task = editor
 6435                    .update(cx, |this, _| this.code_actions_task.take())
 6436                    .ok()?;
 6437            }
 6438
 6439            editor
 6440                .update(cx, |editor, cx| {
 6441                    editor
 6442                        .available_code_actions
 6443                        .clone()
 6444                        .and_then(|(location, code_actions)| {
 6445                            let snapshot = location.buffer.read(cx).snapshot();
 6446                            let point_range = location.range.to_point(&snapshot);
 6447                            let point_range = point_range.start.row..=point_range.end.row;
 6448                            if point_range.contains(&buffer_row) {
 6449                                Some(code_actions)
 6450                            } else {
 6451                                None
 6452                            }
 6453                        })
 6454                })
 6455                .ok()
 6456                .flatten()
 6457        })
 6458    }
 6459
 6460    pub fn confirm_code_action(
 6461        &mut self,
 6462        action: &ConfirmCodeAction,
 6463        window: &mut Window,
 6464        cx: &mut Context<Self>,
 6465    ) -> Option<Task<Result<()>>> {
 6466        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6467
 6468        let actions_menu =
 6469            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6470                menu
 6471            } else {
 6472                return None;
 6473            };
 6474
 6475        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6476        let action = actions_menu.actions.get(action_ix)?;
 6477        let title = action.label();
 6478        let buffer = actions_menu.buffer;
 6479        let workspace = self.workspace()?;
 6480
 6481        match action {
 6482            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6483                workspace.update(cx, |workspace, cx| {
 6484                    workspace.schedule_resolved_task(
 6485                        task_source_kind,
 6486                        resolved_task,
 6487                        false,
 6488                        window,
 6489                        cx,
 6490                    );
 6491
 6492                    Some(Task::ready(Ok(())))
 6493                })
 6494            }
 6495            CodeActionsItem::CodeAction {
 6496                excerpt_id,
 6497                action,
 6498                provider,
 6499            } => {
 6500                let apply_code_action =
 6501                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6502                let workspace = workspace.downgrade();
 6503                Some(cx.spawn_in(window, async move |editor, cx| {
 6504                    let project_transaction = apply_code_action.await?;
 6505                    Self::open_project_transaction(
 6506                        &editor,
 6507                        workspace,
 6508                        project_transaction,
 6509                        title,
 6510                        cx,
 6511                    )
 6512                    .await
 6513                }))
 6514            }
 6515            CodeActionsItem::DebugScenario(scenario) => {
 6516                let context = actions_menu.actions.context;
 6517
 6518                workspace.update(cx, |workspace, cx| {
 6519                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6520                    workspace.start_debug_session(
 6521                        scenario,
 6522                        context,
 6523                        Some(buffer),
 6524                        None,
 6525                        window,
 6526                        cx,
 6527                    );
 6528                });
 6529                Some(Task::ready(Ok(())))
 6530            }
 6531        }
 6532    }
 6533
 6534    pub async fn open_project_transaction(
 6535        editor: &WeakEntity<Editor>,
 6536        workspace: WeakEntity<Workspace>,
 6537        transaction: ProjectTransaction,
 6538        title: String,
 6539        cx: &mut AsyncWindowContext,
 6540    ) -> Result<()> {
 6541        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6542        cx.update(|_, cx| {
 6543            entries.sort_unstable_by_key(|(buffer, _)| {
 6544                buffer.read(cx).file().map(|f| f.path().clone())
 6545            });
 6546        })?;
 6547        if entries.is_empty() {
 6548            return Ok(());
 6549        }
 6550
 6551        // If the project transaction's edits are all contained within this editor, then
 6552        // avoid opening a new editor to display them.
 6553
 6554        if let [(buffer, transaction)] = &*entries {
 6555            let excerpt = editor.update(cx, |editor, cx| {
 6556                editor
 6557                    .buffer()
 6558                    .read(cx)
 6559                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6560            })?;
 6561            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6562                && excerpted_buffer == *buffer
 6563            {
 6564                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6565                    let excerpt_range = excerpt_range.to_offset(buffer);
 6566                    buffer
 6567                        .edited_ranges_for_transaction::<usize>(transaction)
 6568                        .all(|range| {
 6569                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6570                        })
 6571                })?;
 6572
 6573                if all_edits_within_excerpt {
 6574                    return Ok(());
 6575                }
 6576            }
 6577        }
 6578
 6579        let mut ranges_to_highlight = Vec::new();
 6580        let excerpt_buffer = cx.new(|cx| {
 6581            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6582            for (buffer_handle, transaction) in &entries {
 6583                let edited_ranges = buffer_handle
 6584                    .read(cx)
 6585                    .edited_ranges_for_transaction::<Point>(transaction)
 6586                    .collect::<Vec<_>>();
 6587                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6588                    PathKey::for_buffer(buffer_handle, cx),
 6589                    buffer_handle.clone(),
 6590                    edited_ranges,
 6591                    multibuffer_context_lines(cx),
 6592                    cx,
 6593                );
 6594
 6595                ranges_to_highlight.extend(ranges);
 6596            }
 6597            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6598            multibuffer
 6599        })?;
 6600
 6601        workspace.update_in(cx, |workspace, window, cx| {
 6602            let project = workspace.project().clone();
 6603            let editor =
 6604                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6605            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6606            editor.update(cx, |editor, cx| {
 6607                editor.highlight_background::<Self>(
 6608                    &ranges_to_highlight,
 6609                    |theme| theme.colors().editor_highlighted_line_background,
 6610                    cx,
 6611                );
 6612            });
 6613        })?;
 6614
 6615        Ok(())
 6616    }
 6617
 6618    pub fn clear_code_action_providers(&mut self) {
 6619        self.code_action_providers.clear();
 6620        self.available_code_actions.take();
 6621    }
 6622
 6623    pub fn add_code_action_provider(
 6624        &mut self,
 6625        provider: Rc<dyn CodeActionProvider>,
 6626        window: &mut Window,
 6627        cx: &mut Context<Self>,
 6628    ) {
 6629        if self
 6630            .code_action_providers
 6631            .iter()
 6632            .any(|existing_provider| existing_provider.id() == provider.id())
 6633        {
 6634            return;
 6635        }
 6636
 6637        self.code_action_providers.push(provider);
 6638        self.refresh_code_actions(window, cx);
 6639    }
 6640
 6641    pub fn remove_code_action_provider(
 6642        &mut self,
 6643        id: Arc<str>,
 6644        window: &mut Window,
 6645        cx: &mut Context<Self>,
 6646    ) {
 6647        self.code_action_providers
 6648            .retain(|provider| provider.id() != id);
 6649        self.refresh_code_actions(window, cx);
 6650    }
 6651
 6652    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6653        !self.code_action_providers.is_empty()
 6654            && EditorSettings::get_global(cx).toolbar.code_actions
 6655    }
 6656
 6657    pub fn has_available_code_actions(&self) -> bool {
 6658        self.available_code_actions
 6659            .as_ref()
 6660            .is_some_and(|(_, actions)| !actions.is_empty())
 6661    }
 6662
 6663    fn render_inline_code_actions(
 6664        &self,
 6665        icon_size: ui::IconSize,
 6666        display_row: DisplayRow,
 6667        is_active: bool,
 6668        cx: &mut Context<Self>,
 6669    ) -> AnyElement {
 6670        let show_tooltip = !self.context_menu_visible();
 6671        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6672            .icon_size(icon_size)
 6673            .shape(ui::IconButtonShape::Square)
 6674            .icon_color(ui::Color::Hidden)
 6675            .toggle_state(is_active)
 6676            .when(show_tooltip, |this| {
 6677                this.tooltip({
 6678                    let focus_handle = self.focus_handle.clone();
 6679                    move |_window, cx| {
 6680                        Tooltip::for_action_in(
 6681                            "Toggle Code Actions",
 6682                            &ToggleCodeActions {
 6683                                deployed_from: None,
 6684                                quick_launch: false,
 6685                            },
 6686                            &focus_handle,
 6687                            cx,
 6688                        )
 6689                    }
 6690                })
 6691            })
 6692            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6693                window.focus(&editor.focus_handle(cx));
 6694                editor.toggle_code_actions(
 6695                    &crate::actions::ToggleCodeActions {
 6696                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6697                            display_row,
 6698                        )),
 6699                        quick_launch: false,
 6700                    },
 6701                    window,
 6702                    cx,
 6703                );
 6704            }))
 6705            .into_any_element()
 6706    }
 6707
 6708    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6709        &self.context_menu
 6710    }
 6711
 6712    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6713        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6714            cx.background_executor()
 6715                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6716                .await;
 6717
 6718            let (start_buffer, start, _, end, newest_selection) = this
 6719                .update(cx, |this, cx| {
 6720                    let newest_selection = this.selections.newest_anchor().clone();
 6721                    if newest_selection.head().diff_base_anchor.is_some() {
 6722                        return None;
 6723                    }
 6724                    let display_snapshot = this.display_snapshot(cx);
 6725                    let newest_selection_adjusted =
 6726                        this.selections.newest_adjusted(&display_snapshot);
 6727                    let buffer = this.buffer.read(cx);
 6728
 6729                    let (start_buffer, start) =
 6730                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6731                    let (end_buffer, end) =
 6732                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6733
 6734                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6735                })?
 6736                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6737                .context(
 6738                    "Expected selection to lie in a single buffer when refreshing code actions",
 6739                )?;
 6740            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6741                let providers = this.code_action_providers.clone();
 6742                let tasks = this
 6743                    .code_action_providers
 6744                    .iter()
 6745                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6746                    .collect::<Vec<_>>();
 6747                (providers, tasks)
 6748            })?;
 6749
 6750            let mut actions = Vec::new();
 6751            for (provider, provider_actions) in
 6752                providers.into_iter().zip(future::join_all(tasks).await)
 6753            {
 6754                if let Some(provider_actions) = provider_actions.log_err() {
 6755                    actions.extend(provider_actions.into_iter().map(|action| {
 6756                        AvailableCodeAction {
 6757                            excerpt_id: newest_selection.start.excerpt_id,
 6758                            action,
 6759                            provider: provider.clone(),
 6760                        }
 6761                    }));
 6762                }
 6763            }
 6764
 6765            this.update(cx, |this, cx| {
 6766                this.available_code_actions = if actions.is_empty() {
 6767                    None
 6768                } else {
 6769                    Some((
 6770                        Location {
 6771                            buffer: start_buffer,
 6772                            range: start..end,
 6773                        },
 6774                        actions.into(),
 6775                    ))
 6776                };
 6777                cx.notify();
 6778            })
 6779        }));
 6780    }
 6781
 6782    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6783        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6784            self.show_git_blame_inline = false;
 6785
 6786            self.show_git_blame_inline_delay_task =
 6787                Some(cx.spawn_in(window, async move |this, cx| {
 6788                    cx.background_executor().timer(delay).await;
 6789
 6790                    this.update(cx, |this, cx| {
 6791                        this.show_git_blame_inline = true;
 6792                        cx.notify();
 6793                    })
 6794                    .log_err();
 6795                }));
 6796        }
 6797    }
 6798
 6799    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6800        let snapshot = self.snapshot(window, cx);
 6801        let cursor = self
 6802            .selections
 6803            .newest::<Point>(&snapshot.display_snapshot)
 6804            .head();
 6805        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6806        else {
 6807            return;
 6808        };
 6809
 6810        let Some(blame) = self.blame.as_ref() else {
 6811            return;
 6812        };
 6813
 6814        let row_info = RowInfo {
 6815            buffer_id: Some(buffer.remote_id()),
 6816            buffer_row: Some(point.row),
 6817            ..Default::default()
 6818        };
 6819        let Some((buffer, blame_entry)) = blame
 6820            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6821            .flatten()
 6822        else {
 6823            return;
 6824        };
 6825
 6826        let anchor = self.selections.newest_anchor().head();
 6827        let position = self.to_pixel_point(anchor, &snapshot, window);
 6828        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6829            self.show_blame_popover(
 6830                buffer,
 6831                &blame_entry,
 6832                position + last_bounds.origin,
 6833                true,
 6834                cx,
 6835            );
 6836        };
 6837    }
 6838
 6839    fn show_blame_popover(
 6840        &mut self,
 6841        buffer: BufferId,
 6842        blame_entry: &BlameEntry,
 6843        position: gpui::Point<Pixels>,
 6844        ignore_timeout: bool,
 6845        cx: &mut Context<Self>,
 6846    ) {
 6847        if let Some(state) = &mut self.inline_blame_popover {
 6848            state.hide_task.take();
 6849        } else {
 6850            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6851            let blame_entry = blame_entry.clone();
 6852            let show_task = cx.spawn(async move |editor, cx| {
 6853                if !ignore_timeout {
 6854                    cx.background_executor()
 6855                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6856                        .await;
 6857                }
 6858                editor
 6859                    .update(cx, |editor, cx| {
 6860                        editor.inline_blame_popover_show_task.take();
 6861                        let Some(blame) = editor.blame.as_ref() else {
 6862                            return;
 6863                        };
 6864                        let blame = blame.read(cx);
 6865                        let details = blame.details_for_entry(buffer, &blame_entry);
 6866                        let markdown = cx.new(|cx| {
 6867                            Markdown::new(
 6868                                details
 6869                                    .as_ref()
 6870                                    .map(|message| message.message.clone())
 6871                                    .unwrap_or_default(),
 6872                                None,
 6873                                None,
 6874                                cx,
 6875                            )
 6876                        });
 6877                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6878                            position,
 6879                            hide_task: None,
 6880                            popover_bounds: None,
 6881                            popover_state: InlineBlamePopoverState {
 6882                                scroll_handle: ScrollHandle::new(),
 6883                                commit_message: details,
 6884                                markdown,
 6885                            },
 6886                            keyboard_grace: ignore_timeout,
 6887                        });
 6888                        cx.notify();
 6889                    })
 6890                    .ok();
 6891            });
 6892            self.inline_blame_popover_show_task = Some(show_task);
 6893        }
 6894    }
 6895
 6896    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6897        self.inline_blame_popover_show_task.take();
 6898        if let Some(state) = &mut self.inline_blame_popover {
 6899            let hide_task = cx.spawn(async move |editor, cx| {
 6900                if !ignore_timeout {
 6901                    cx.background_executor()
 6902                        .timer(std::time::Duration::from_millis(100))
 6903                        .await;
 6904                }
 6905                editor
 6906                    .update(cx, |editor, cx| {
 6907                        editor.inline_blame_popover.take();
 6908                        cx.notify();
 6909                    })
 6910                    .ok();
 6911            });
 6912            state.hide_task = Some(hide_task);
 6913            true
 6914        } else {
 6915            false
 6916        }
 6917    }
 6918
 6919    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6920        if self.pending_rename.is_some() {
 6921            return None;
 6922        }
 6923
 6924        let provider = self.semantics_provider.clone()?;
 6925        let buffer = self.buffer.read(cx);
 6926        let newest_selection = self.selections.newest_anchor().clone();
 6927        let cursor_position = newest_selection.head();
 6928        let (cursor_buffer, cursor_buffer_position) =
 6929            buffer.text_anchor_for_position(cursor_position, cx)?;
 6930        let (tail_buffer, tail_buffer_position) =
 6931            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6932        if cursor_buffer != tail_buffer {
 6933            return None;
 6934        }
 6935
 6936        let snapshot = cursor_buffer.read(cx).snapshot();
 6937        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6938        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6939        if start_word_range != end_word_range {
 6940            self.document_highlights_task.take();
 6941            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6942            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6943            return None;
 6944        }
 6945
 6946        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6947        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6948            cx.background_executor()
 6949                .timer(Duration::from_millis(debounce))
 6950                .await;
 6951
 6952            let highlights = if let Some(highlights) = cx
 6953                .update(|cx| {
 6954                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6955                })
 6956                .ok()
 6957                .flatten()
 6958            {
 6959                highlights.await.log_err()
 6960            } else {
 6961                None
 6962            };
 6963
 6964            if let Some(highlights) = highlights {
 6965                this.update(cx, |this, cx| {
 6966                    if this.pending_rename.is_some() {
 6967                        return;
 6968                    }
 6969
 6970                    let buffer = this.buffer.read(cx);
 6971                    if buffer
 6972                        .text_anchor_for_position(cursor_position, cx)
 6973                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6974                    {
 6975                        return;
 6976                    }
 6977
 6978                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6979                    let mut write_ranges = Vec::new();
 6980                    let mut read_ranges = Vec::new();
 6981                    for highlight in highlights {
 6982                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6983                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6984                        {
 6985                            let start = highlight
 6986                                .range
 6987                                .start
 6988                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6989                            let end = highlight
 6990                                .range
 6991                                .end
 6992                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6993                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6994                                continue;
 6995                            }
 6996
 6997                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 6998                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6999                                write_ranges.push(range);
 7000                            } else {
 7001                                read_ranges.push(range);
 7002                            }
 7003                        }
 7004                    }
 7005
 7006                    this.highlight_background::<DocumentHighlightRead>(
 7007                        &read_ranges,
 7008                        |theme| theme.colors().editor_document_highlight_read_background,
 7009                        cx,
 7010                    );
 7011                    this.highlight_background::<DocumentHighlightWrite>(
 7012                        &write_ranges,
 7013                        |theme| theme.colors().editor_document_highlight_write_background,
 7014                        cx,
 7015                    );
 7016                    cx.notify();
 7017                })
 7018                .log_err();
 7019            }
 7020        }));
 7021        None
 7022    }
 7023
 7024    fn prepare_highlight_query_from_selection(
 7025        &mut self,
 7026        window: &Window,
 7027        cx: &mut Context<Editor>,
 7028    ) -> Option<(String, Range<Anchor>)> {
 7029        if matches!(self.mode, EditorMode::SingleLine) {
 7030            return None;
 7031        }
 7032        if !EditorSettings::get_global(cx).selection_highlight {
 7033            return None;
 7034        }
 7035        if self.selections.count() != 1 || self.selections.line_mode() {
 7036            return None;
 7037        }
 7038        let snapshot = self.snapshot(window, cx);
 7039        let selection = self.selections.newest::<Point>(&snapshot);
 7040        // If the selection spans multiple rows OR it is empty
 7041        if selection.start.row != selection.end.row
 7042            || selection.start.column == selection.end.column
 7043        {
 7044            return None;
 7045        }
 7046        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7047        let query = snapshot
 7048            .buffer_snapshot()
 7049            .text_for_range(selection_anchor_range.clone())
 7050            .collect::<String>();
 7051        if query.trim().is_empty() {
 7052            return None;
 7053        }
 7054        Some((query, selection_anchor_range))
 7055    }
 7056
 7057    fn update_selection_occurrence_highlights(
 7058        &mut self,
 7059        query_text: String,
 7060        query_range: Range<Anchor>,
 7061        multi_buffer_range_to_query: Range<Point>,
 7062        use_debounce: bool,
 7063        window: &mut Window,
 7064        cx: &mut Context<Editor>,
 7065    ) -> Task<()> {
 7066        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7067        cx.spawn_in(window, async move |editor, cx| {
 7068            if use_debounce {
 7069                cx.background_executor()
 7070                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7071                    .await;
 7072            }
 7073            let match_task = cx.background_spawn(async move {
 7074                let buffer_ranges = multi_buffer_snapshot
 7075                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7076                    .into_iter()
 7077                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7078                let mut match_ranges = Vec::new();
 7079                let Ok(regex) = project::search::SearchQuery::text(
 7080                    query_text.clone(),
 7081                    false,
 7082                    false,
 7083                    false,
 7084                    Default::default(),
 7085                    Default::default(),
 7086                    false,
 7087                    None,
 7088                ) else {
 7089                    return Vec::default();
 7090                };
 7091                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7092                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7093                    match_ranges.extend(
 7094                        regex
 7095                            .search(
 7096                                buffer_snapshot,
 7097                                Some(search_range.start.0..search_range.end.0),
 7098                            )
 7099                            .await
 7100                            .into_iter()
 7101                            .filter_map(|match_range| {
 7102                                let match_start = buffer_snapshot
 7103                                    .anchor_after(search_range.start + match_range.start);
 7104                                let match_end = buffer_snapshot
 7105                                    .anchor_before(search_range.start + match_range.end);
 7106                                let match_anchor_range =
 7107                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7108                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7109                            }),
 7110                    );
 7111                }
 7112                match_ranges
 7113            });
 7114            let match_ranges = match_task.await;
 7115            editor
 7116                .update_in(cx, |editor, _, cx| {
 7117                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7118                    if !match_ranges.is_empty() {
 7119                        editor.highlight_background::<SelectedTextHighlight>(
 7120                            &match_ranges,
 7121                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7122                            cx,
 7123                        )
 7124                    }
 7125                })
 7126                .log_err();
 7127        })
 7128    }
 7129
 7130    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7131        struct NewlineFold;
 7132        let type_id = std::any::TypeId::of::<NewlineFold>();
 7133        if !self.mode.is_single_line() {
 7134            return;
 7135        }
 7136        let snapshot = self.snapshot(window, cx);
 7137        if snapshot.buffer_snapshot().max_point().row == 0 {
 7138            return;
 7139        }
 7140        let task = cx.background_spawn(async move {
 7141            let new_newlines = snapshot
 7142                .buffer_chars_at(MultiBufferOffset(0))
 7143                .filter_map(|(c, i)| {
 7144                    if c == '\n' {
 7145                        Some(
 7146                            snapshot.buffer_snapshot().anchor_after(i)
 7147                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7148                        )
 7149                    } else {
 7150                        None
 7151                    }
 7152                })
 7153                .collect::<Vec<_>>();
 7154            let existing_newlines = snapshot
 7155                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7156                .filter_map(|fold| {
 7157                    if fold.placeholder.type_tag == Some(type_id) {
 7158                        Some(fold.range.start..fold.range.end)
 7159                    } else {
 7160                        None
 7161                    }
 7162                })
 7163                .collect::<Vec<_>>();
 7164
 7165            (new_newlines, existing_newlines)
 7166        });
 7167        self.folding_newlines = cx.spawn(async move |this, cx| {
 7168            let (new_newlines, existing_newlines) = task.await;
 7169            if new_newlines == existing_newlines {
 7170                return;
 7171            }
 7172            let placeholder = FoldPlaceholder {
 7173                render: Arc::new(move |_, _, cx| {
 7174                    div()
 7175                        .bg(cx.theme().status().hint_background)
 7176                        .border_b_1()
 7177                        .size_full()
 7178                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7179                        .border_color(cx.theme().status().hint)
 7180                        .child("\\n")
 7181                        .into_any()
 7182                }),
 7183                constrain_width: false,
 7184                merge_adjacent: false,
 7185                type_tag: Some(type_id),
 7186            };
 7187            let creases = new_newlines
 7188                .into_iter()
 7189                .map(|range| Crease::simple(range, placeholder.clone()))
 7190                .collect();
 7191            this.update(cx, |this, cx| {
 7192                this.display_map.update(cx, |display_map, cx| {
 7193                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7194                    display_map.fold(creases, cx);
 7195                });
 7196            })
 7197            .ok();
 7198        });
 7199    }
 7200
 7201    fn refresh_selected_text_highlights(
 7202        &mut self,
 7203        on_buffer_edit: bool,
 7204        window: &mut Window,
 7205        cx: &mut Context<Editor>,
 7206    ) {
 7207        let Some((query_text, query_range)) =
 7208            self.prepare_highlight_query_from_selection(window, cx)
 7209        else {
 7210            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7211            self.quick_selection_highlight_task.take();
 7212            self.debounced_selection_highlight_task.take();
 7213            return;
 7214        };
 7215        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7216        if on_buffer_edit
 7217            || self
 7218                .quick_selection_highlight_task
 7219                .as_ref()
 7220                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7221        {
 7222            let multi_buffer_visible_start = self
 7223                .scroll_manager
 7224                .anchor()
 7225                .anchor
 7226                .to_point(&multi_buffer_snapshot);
 7227            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7228                multi_buffer_visible_start
 7229                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7230                Bias::Left,
 7231            );
 7232            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7233            self.quick_selection_highlight_task = Some((
 7234                query_range.clone(),
 7235                self.update_selection_occurrence_highlights(
 7236                    query_text.clone(),
 7237                    query_range.clone(),
 7238                    multi_buffer_visible_range,
 7239                    false,
 7240                    window,
 7241                    cx,
 7242                ),
 7243            ));
 7244        }
 7245        if on_buffer_edit
 7246            || self
 7247                .debounced_selection_highlight_task
 7248                .as_ref()
 7249                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7250        {
 7251            let multi_buffer_start = multi_buffer_snapshot
 7252                .anchor_before(MultiBufferOffset(0))
 7253                .to_point(&multi_buffer_snapshot);
 7254            let multi_buffer_end = multi_buffer_snapshot
 7255                .anchor_after(multi_buffer_snapshot.len())
 7256                .to_point(&multi_buffer_snapshot);
 7257            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7258            self.debounced_selection_highlight_task = Some((
 7259                query_range.clone(),
 7260                self.update_selection_occurrence_highlights(
 7261                    query_text,
 7262                    query_range,
 7263                    multi_buffer_full_range,
 7264                    true,
 7265                    window,
 7266                    cx,
 7267                ),
 7268            ));
 7269        }
 7270    }
 7271
 7272    pub fn refresh_edit_prediction(
 7273        &mut self,
 7274        debounce: bool,
 7275        user_requested: bool,
 7276        window: &mut Window,
 7277        cx: &mut Context<Self>,
 7278    ) -> Option<()> {
 7279        if DisableAiSettings::get_global(cx).disable_ai {
 7280            return None;
 7281        }
 7282
 7283        let provider = self.edit_prediction_provider()?;
 7284        let cursor = self.selections.newest_anchor().head();
 7285        let (buffer, cursor_buffer_position) =
 7286            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7287
 7288        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7289            self.discard_edit_prediction(false, cx);
 7290            return None;
 7291        }
 7292
 7293        self.update_visible_edit_prediction(window, cx);
 7294
 7295        if !user_requested
 7296            && (!self.should_show_edit_predictions()
 7297                || !self.is_focused(window)
 7298                || buffer.read(cx).is_empty())
 7299        {
 7300            self.discard_edit_prediction(false, cx);
 7301            return None;
 7302        }
 7303
 7304        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7305        Some(())
 7306    }
 7307
 7308    fn show_edit_predictions_in_menu(&self) -> bool {
 7309        match self.edit_prediction_settings {
 7310            EditPredictionSettings::Disabled => false,
 7311            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7312        }
 7313    }
 7314
 7315    pub fn edit_predictions_enabled(&self) -> bool {
 7316        match self.edit_prediction_settings {
 7317            EditPredictionSettings::Disabled => false,
 7318            EditPredictionSettings::Enabled { .. } => true,
 7319        }
 7320    }
 7321
 7322    fn edit_prediction_requires_modifier(&self) -> bool {
 7323        match self.edit_prediction_settings {
 7324            EditPredictionSettings::Disabled => false,
 7325            EditPredictionSettings::Enabled {
 7326                preview_requires_modifier,
 7327                ..
 7328            } => preview_requires_modifier,
 7329        }
 7330    }
 7331
 7332    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7333        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7334            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7335            self.discard_edit_prediction(false, cx);
 7336        } else {
 7337            let selection = self.selections.newest_anchor();
 7338            let cursor = selection.head();
 7339
 7340            if let Some((buffer, cursor_buffer_position)) =
 7341                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7342            {
 7343                self.edit_prediction_settings =
 7344                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7345            }
 7346        }
 7347    }
 7348
 7349    fn edit_prediction_settings_at_position(
 7350        &self,
 7351        buffer: &Entity<Buffer>,
 7352        buffer_position: language::Anchor,
 7353        cx: &App,
 7354    ) -> EditPredictionSettings {
 7355        if !self.mode.is_full()
 7356            || !self.show_edit_predictions_override.unwrap_or(true)
 7357            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7358        {
 7359            return EditPredictionSettings::Disabled;
 7360        }
 7361
 7362        let buffer = buffer.read(cx);
 7363
 7364        let file = buffer.file();
 7365
 7366        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7367            return EditPredictionSettings::Disabled;
 7368        };
 7369
 7370        let by_provider = matches!(
 7371            self.menu_edit_predictions_policy,
 7372            MenuEditPredictionsPolicy::ByProvider
 7373        );
 7374
 7375        let show_in_menu = by_provider
 7376            && self
 7377                .edit_prediction_provider
 7378                .as_ref()
 7379                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7380
 7381        let preview_requires_modifier =
 7382            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7383
 7384        EditPredictionSettings::Enabled {
 7385            show_in_menu,
 7386            preview_requires_modifier,
 7387        }
 7388    }
 7389
 7390    fn should_show_edit_predictions(&self) -> bool {
 7391        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7392    }
 7393
 7394    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7395        matches!(
 7396            self.edit_prediction_preview,
 7397            EditPredictionPreview::Active { .. }
 7398        )
 7399    }
 7400
 7401    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7402        let cursor = self.selections.newest_anchor().head();
 7403        if let Some((buffer, cursor_position)) =
 7404            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7405        {
 7406            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7407        } else {
 7408            false
 7409        }
 7410    }
 7411
 7412    pub fn supports_minimap(&self, cx: &App) -> bool {
 7413        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7414    }
 7415
 7416    fn edit_predictions_enabled_in_buffer(
 7417        &self,
 7418        buffer: &Entity<Buffer>,
 7419        buffer_position: language::Anchor,
 7420        cx: &App,
 7421    ) -> bool {
 7422        maybe!({
 7423            if self.read_only(cx) {
 7424                return Some(false);
 7425            }
 7426            let provider = self.edit_prediction_provider()?;
 7427            if !provider.is_enabled(buffer, buffer_position, cx) {
 7428                return Some(false);
 7429            }
 7430            let buffer = buffer.read(cx);
 7431            let Some(file) = buffer.file() else {
 7432                return Some(true);
 7433            };
 7434            let settings = all_language_settings(Some(file), cx);
 7435            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7436        })
 7437        .unwrap_or(false)
 7438    }
 7439
 7440    fn cycle_edit_prediction(
 7441        &mut self,
 7442        direction: Direction,
 7443        window: &mut Window,
 7444        cx: &mut Context<Self>,
 7445    ) -> Option<()> {
 7446        let provider = self.edit_prediction_provider()?;
 7447        let cursor = self.selections.newest_anchor().head();
 7448        let (buffer, cursor_buffer_position) =
 7449            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7450        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7451            return None;
 7452        }
 7453
 7454        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7455        self.update_visible_edit_prediction(window, cx);
 7456
 7457        Some(())
 7458    }
 7459
 7460    pub fn show_edit_prediction(
 7461        &mut self,
 7462        _: &ShowEditPrediction,
 7463        window: &mut Window,
 7464        cx: &mut Context<Self>,
 7465    ) {
 7466        if !self.has_active_edit_prediction() {
 7467            self.refresh_edit_prediction(false, true, window, cx);
 7468            return;
 7469        }
 7470
 7471        self.update_visible_edit_prediction(window, cx);
 7472    }
 7473
 7474    pub fn display_cursor_names(
 7475        &mut self,
 7476        _: &DisplayCursorNames,
 7477        window: &mut Window,
 7478        cx: &mut Context<Self>,
 7479    ) {
 7480        self.show_cursor_names(window, cx);
 7481    }
 7482
 7483    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7484        self.show_cursor_names = true;
 7485        cx.notify();
 7486        cx.spawn_in(window, async move |this, cx| {
 7487            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7488            this.update(cx, |this, cx| {
 7489                this.show_cursor_names = false;
 7490                cx.notify()
 7491            })
 7492            .ok()
 7493        })
 7494        .detach();
 7495    }
 7496
 7497    pub fn next_edit_prediction(
 7498        &mut self,
 7499        _: &NextEditPrediction,
 7500        window: &mut Window,
 7501        cx: &mut Context<Self>,
 7502    ) {
 7503        if self.has_active_edit_prediction() {
 7504            self.cycle_edit_prediction(Direction::Next, window, cx);
 7505        } else {
 7506            let is_copilot_disabled = self
 7507                .refresh_edit_prediction(false, true, window, cx)
 7508                .is_none();
 7509            if is_copilot_disabled {
 7510                cx.propagate();
 7511            }
 7512        }
 7513    }
 7514
 7515    pub fn previous_edit_prediction(
 7516        &mut self,
 7517        _: &PreviousEditPrediction,
 7518        window: &mut Window,
 7519        cx: &mut Context<Self>,
 7520    ) {
 7521        if self.has_active_edit_prediction() {
 7522            self.cycle_edit_prediction(Direction::Prev, 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 accept_edit_prediction(
 7534        &mut self,
 7535        _: &AcceptEditPrediction,
 7536        window: &mut Window,
 7537        cx: &mut Context<Self>,
 7538    ) {
 7539        if self.show_edit_predictions_in_menu() {
 7540            self.hide_context_menu(window, cx);
 7541        }
 7542
 7543        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7544            return;
 7545        };
 7546
 7547        match &active_edit_prediction.completion {
 7548            EditPrediction::MoveWithin { target, .. } => {
 7549                let target = *target;
 7550
 7551                if let Some(position_map) = &self.last_position_map {
 7552                    if position_map
 7553                        .visible_row_range
 7554                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7555                        || !self.edit_prediction_requires_modifier()
 7556                    {
 7557                        self.unfold_ranges(&[target..target], true, false, cx);
 7558                        // Note that this is also done in vim's handler of the Tab action.
 7559                        self.change_selections(
 7560                            SelectionEffects::scroll(Autoscroll::newest()),
 7561                            window,
 7562                            cx,
 7563                            |selections| {
 7564                                selections.select_anchor_ranges([target..target]);
 7565                            },
 7566                        );
 7567                        self.clear_row_highlights::<EditPredictionPreview>();
 7568
 7569                        self.edit_prediction_preview
 7570                            .set_previous_scroll_position(None);
 7571                    } else {
 7572                        self.edit_prediction_preview
 7573                            .set_previous_scroll_position(Some(
 7574                                position_map.snapshot.scroll_anchor,
 7575                            ));
 7576
 7577                        self.highlight_rows::<EditPredictionPreview>(
 7578                            target..target,
 7579                            cx.theme().colors().editor_highlighted_line_background,
 7580                            RowHighlightOptions {
 7581                                autoscroll: true,
 7582                                ..Default::default()
 7583                            },
 7584                            cx,
 7585                        );
 7586                        self.request_autoscroll(Autoscroll::fit(), cx);
 7587                    }
 7588                }
 7589            }
 7590            EditPrediction::MoveOutside { snapshot, target } => {
 7591                if let Some(workspace) = self.workspace() {
 7592                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7593                        .detach_and_log_err(cx);
 7594                }
 7595            }
 7596            EditPrediction::Edit { edits, .. } => {
 7597                self.report_edit_prediction_event(
 7598                    active_edit_prediction.completion_id.clone(),
 7599                    true,
 7600                    cx,
 7601                );
 7602
 7603                if let Some(provider) = self.edit_prediction_provider() {
 7604                    provider.accept(cx);
 7605                }
 7606
 7607                // Store the transaction ID and selections before applying the edit
 7608                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7609
 7610                let snapshot = self.buffer.read(cx).snapshot(cx);
 7611                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7612
 7613                self.buffer.update(cx, |buffer, cx| {
 7614                    buffer.edit(edits.iter().cloned(), None, cx)
 7615                });
 7616
 7617                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7618                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7619                });
 7620
 7621                let selections = self.selections.disjoint_anchors_arc();
 7622                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7623                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7624                    if has_new_transaction {
 7625                        self.selection_history
 7626                            .insert_transaction(transaction_id_now, selections);
 7627                    }
 7628                }
 7629
 7630                self.update_visible_edit_prediction(window, cx);
 7631                if self.active_edit_prediction.is_none() {
 7632                    self.refresh_edit_prediction(true, true, window, cx);
 7633                }
 7634
 7635                cx.notify();
 7636            }
 7637        }
 7638
 7639        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7640    }
 7641
 7642    pub fn accept_partial_edit_prediction(
 7643        &mut self,
 7644        _: &AcceptPartialEditPrediction,
 7645        window: &mut Window,
 7646        cx: &mut Context<Self>,
 7647    ) {
 7648        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7649            return;
 7650        };
 7651        if self.selections.count() != 1 {
 7652            return;
 7653        }
 7654
 7655        match &active_edit_prediction.completion {
 7656            EditPrediction::MoveWithin { target, .. } => {
 7657                let target = *target;
 7658                self.change_selections(
 7659                    SelectionEffects::scroll(Autoscroll::newest()),
 7660                    window,
 7661                    cx,
 7662                    |selections| {
 7663                        selections.select_anchor_ranges([target..target]);
 7664                    },
 7665                );
 7666            }
 7667            EditPrediction::MoveOutside { snapshot, target } => {
 7668                if let Some(workspace) = self.workspace() {
 7669                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7670                        .detach_and_log_err(cx);
 7671                }
 7672            }
 7673            EditPrediction::Edit { edits, .. } => {
 7674                self.report_edit_prediction_event(
 7675                    active_edit_prediction.completion_id.clone(),
 7676                    true,
 7677                    cx,
 7678                );
 7679
 7680                // Find an insertion that starts at the cursor position.
 7681                let snapshot = self.buffer.read(cx).snapshot(cx);
 7682                let cursor_offset = self
 7683                    .selections
 7684                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7685                    .head();
 7686                let insertion = edits.iter().find_map(|(range, text)| {
 7687                    let range = range.to_offset(&snapshot);
 7688                    if range.is_empty() && range.start == cursor_offset {
 7689                        Some(text)
 7690                    } else {
 7691                        None
 7692                    }
 7693                });
 7694
 7695                if let Some(text) = insertion {
 7696                    let mut partial_completion = text
 7697                        .chars()
 7698                        .by_ref()
 7699                        .take_while(|c| c.is_alphabetic())
 7700                        .collect::<String>();
 7701                    if partial_completion.is_empty() {
 7702                        partial_completion = text
 7703                            .chars()
 7704                            .by_ref()
 7705                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7706                            .collect::<String>();
 7707                    }
 7708
 7709                    cx.emit(EditorEvent::InputHandled {
 7710                        utf16_range_to_replace: None,
 7711                        text: partial_completion.clone().into(),
 7712                    });
 7713
 7714                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7715
 7716                    self.refresh_edit_prediction(true, true, window, cx);
 7717                    cx.notify();
 7718                } else {
 7719                    self.accept_edit_prediction(&Default::default(), window, cx);
 7720                }
 7721            }
 7722        }
 7723    }
 7724
 7725    fn discard_edit_prediction(
 7726        &mut self,
 7727        should_report_edit_prediction_event: bool,
 7728        cx: &mut Context<Self>,
 7729    ) -> bool {
 7730        if should_report_edit_prediction_event {
 7731            let completion_id = self
 7732                .active_edit_prediction
 7733                .as_ref()
 7734                .and_then(|active_completion| active_completion.completion_id.clone());
 7735
 7736            self.report_edit_prediction_event(completion_id, false, cx);
 7737        }
 7738
 7739        if let Some(provider) = self.edit_prediction_provider() {
 7740            provider.discard(cx);
 7741        }
 7742
 7743        self.take_active_edit_prediction(cx)
 7744    }
 7745
 7746    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7747        let Some(provider) = self.edit_prediction_provider() else {
 7748            return;
 7749        };
 7750
 7751        let Some((_, buffer, _)) = self
 7752            .buffer
 7753            .read(cx)
 7754            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7755        else {
 7756            return;
 7757        };
 7758
 7759        let extension = buffer
 7760            .read(cx)
 7761            .file()
 7762            .and_then(|file| Some(file.path().extension()?.to_string()));
 7763
 7764        let event_type = match accepted {
 7765            true => "Edit Prediction Accepted",
 7766            false => "Edit Prediction Discarded",
 7767        };
 7768        telemetry::event!(
 7769            event_type,
 7770            provider = provider.name(),
 7771            prediction_id = id,
 7772            suggestion_accepted = accepted,
 7773            file_extension = extension,
 7774        );
 7775    }
 7776
 7777    fn open_editor_at_anchor(
 7778        snapshot: &language::BufferSnapshot,
 7779        target: language::Anchor,
 7780        workspace: &Entity<Workspace>,
 7781        window: &mut Window,
 7782        cx: &mut App,
 7783    ) -> Task<Result<()>> {
 7784        workspace.update(cx, |workspace, cx| {
 7785            let path = snapshot.file().map(|file| file.full_path(cx));
 7786            let Some(path) =
 7787                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7788            else {
 7789                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7790            };
 7791            let target = text::ToPoint::to_point(&target, snapshot);
 7792            let item = workspace.open_path(path, None, true, window, cx);
 7793            window.spawn(cx, async move |cx| {
 7794                let Some(editor) = item.await?.downcast::<Editor>() else {
 7795                    return Ok(());
 7796                };
 7797                editor
 7798                    .update_in(cx, |editor, window, cx| {
 7799                        editor.go_to_singleton_buffer_point(target, window, cx);
 7800                    })
 7801                    .ok();
 7802                anyhow::Ok(())
 7803            })
 7804        })
 7805    }
 7806
 7807    pub fn has_active_edit_prediction(&self) -> bool {
 7808        self.active_edit_prediction.is_some()
 7809    }
 7810
 7811    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7812        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7813            return false;
 7814        };
 7815
 7816        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7817        self.clear_highlights::<EditPredictionHighlight>(cx);
 7818        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7819        true
 7820    }
 7821
 7822    /// Returns true when we're displaying the edit prediction popover below the cursor
 7823    /// like we are not previewing and the LSP autocomplete menu is visible
 7824    /// or we are in `when_holding_modifier` mode.
 7825    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7826        if self.edit_prediction_preview_is_active()
 7827            || !self.show_edit_predictions_in_menu()
 7828            || !self.edit_predictions_enabled()
 7829        {
 7830            return false;
 7831        }
 7832
 7833        if self.has_visible_completions_menu() {
 7834            return true;
 7835        }
 7836
 7837        has_completion && self.edit_prediction_requires_modifier()
 7838    }
 7839
 7840    fn handle_modifiers_changed(
 7841        &mut self,
 7842        modifiers: Modifiers,
 7843        position_map: &PositionMap,
 7844        window: &mut Window,
 7845        cx: &mut Context<Self>,
 7846    ) {
 7847        // Ensure that the edit prediction preview is updated, even when not
 7848        // enabled, if there's an active edit prediction preview.
 7849        if self.show_edit_predictions_in_menu()
 7850            || matches!(
 7851                self.edit_prediction_preview,
 7852                EditPredictionPreview::Active { .. }
 7853            )
 7854        {
 7855            self.update_edit_prediction_preview(&modifiers, window, cx);
 7856        }
 7857
 7858        self.update_selection_mode(&modifiers, position_map, window, cx);
 7859
 7860        let mouse_position = window.mouse_position();
 7861        if !position_map.text_hitbox.is_hovered(window) {
 7862            return;
 7863        }
 7864
 7865        self.update_hovered_link(
 7866            position_map.point_for_position(mouse_position),
 7867            &position_map.snapshot,
 7868            modifiers,
 7869            window,
 7870            cx,
 7871        )
 7872    }
 7873
 7874    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7875        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7876            MultiCursorModifier::Alt => modifiers.secondary(),
 7877            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7878        }
 7879    }
 7880
 7881    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7882        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7883            MultiCursorModifier::Alt => modifiers.alt,
 7884            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7885        }
 7886    }
 7887
 7888    fn columnar_selection_mode(
 7889        modifiers: &Modifiers,
 7890        cx: &mut Context<Self>,
 7891    ) -> Option<ColumnarMode> {
 7892        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7893            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7894                Some(ColumnarMode::FromMouse)
 7895            } else if Self::is_alt_pressed(modifiers, cx) {
 7896                Some(ColumnarMode::FromSelection)
 7897            } else {
 7898                None
 7899            }
 7900        } else {
 7901            None
 7902        }
 7903    }
 7904
 7905    fn update_selection_mode(
 7906        &mut self,
 7907        modifiers: &Modifiers,
 7908        position_map: &PositionMap,
 7909        window: &mut Window,
 7910        cx: &mut Context<Self>,
 7911    ) {
 7912        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7913            return;
 7914        };
 7915        if self.selections.pending_anchor().is_none() {
 7916            return;
 7917        }
 7918
 7919        let mouse_position = window.mouse_position();
 7920        let point_for_position = position_map.point_for_position(mouse_position);
 7921        let position = point_for_position.previous_valid;
 7922
 7923        self.select(
 7924            SelectPhase::BeginColumnar {
 7925                position,
 7926                reset: false,
 7927                mode,
 7928                goal_column: point_for_position.exact_unclipped.column(),
 7929            },
 7930            window,
 7931            cx,
 7932        );
 7933    }
 7934
 7935    fn update_edit_prediction_preview(
 7936        &mut self,
 7937        modifiers: &Modifiers,
 7938        window: &mut Window,
 7939        cx: &mut Context<Self>,
 7940    ) {
 7941        let mut modifiers_held = false;
 7942        if let Some(accept_keystroke) = self
 7943            .accept_edit_prediction_keybind(false, window, cx)
 7944            .keystroke()
 7945        {
 7946            modifiers_held = modifiers_held
 7947                || (accept_keystroke.modifiers() == modifiers
 7948                    && accept_keystroke.modifiers().modified());
 7949        };
 7950        if let Some(accept_partial_keystroke) = self
 7951            .accept_edit_prediction_keybind(true, window, cx)
 7952            .keystroke()
 7953        {
 7954            modifiers_held = modifiers_held
 7955                || (accept_partial_keystroke.modifiers() == modifiers
 7956                    && accept_partial_keystroke.modifiers().modified());
 7957        }
 7958
 7959        if modifiers_held {
 7960            if matches!(
 7961                self.edit_prediction_preview,
 7962                EditPredictionPreview::Inactive { .. }
 7963            ) {
 7964                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7965                    provider.provider.did_show(cx)
 7966                }
 7967
 7968                self.edit_prediction_preview = EditPredictionPreview::Active {
 7969                    previous_scroll_position: None,
 7970                    since: Instant::now(),
 7971                };
 7972
 7973                self.update_visible_edit_prediction(window, cx);
 7974                cx.notify();
 7975            }
 7976        } else if let EditPredictionPreview::Active {
 7977            previous_scroll_position,
 7978            since,
 7979        } = self.edit_prediction_preview
 7980        {
 7981            if let (Some(previous_scroll_position), Some(position_map)) =
 7982                (previous_scroll_position, self.last_position_map.as_ref())
 7983            {
 7984                self.set_scroll_position(
 7985                    previous_scroll_position
 7986                        .scroll_position(&position_map.snapshot.display_snapshot),
 7987                    window,
 7988                    cx,
 7989                );
 7990            }
 7991
 7992            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7993                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7994            };
 7995            self.clear_row_highlights::<EditPredictionPreview>();
 7996            self.update_visible_edit_prediction(window, cx);
 7997            cx.notify();
 7998        }
 7999    }
 8000
 8001    fn update_visible_edit_prediction(
 8002        &mut self,
 8003        _window: &mut Window,
 8004        cx: &mut Context<Self>,
 8005    ) -> Option<()> {
 8006        if DisableAiSettings::get_global(cx).disable_ai {
 8007            return None;
 8008        }
 8009
 8010        if self.ime_transaction.is_some() {
 8011            self.discard_edit_prediction(false, cx);
 8012            return None;
 8013        }
 8014
 8015        let selection = self.selections.newest_anchor();
 8016        let cursor = selection.head();
 8017        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8018        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8019        let excerpt_id = cursor.excerpt_id;
 8020
 8021        let show_in_menu = self.show_edit_predictions_in_menu();
 8022        let completions_menu_has_precedence = !show_in_menu
 8023            && (self.context_menu.borrow().is_some()
 8024                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8025
 8026        if completions_menu_has_precedence
 8027            || !offset_selection.is_empty()
 8028            || self
 8029                .active_edit_prediction
 8030                .as_ref()
 8031                .is_some_and(|completion| {
 8032                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8033                        return false;
 8034                    };
 8035                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8036                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8037                    !invalidation_range.contains(&offset_selection.head())
 8038                })
 8039        {
 8040            self.discard_edit_prediction(false, cx);
 8041            return None;
 8042        }
 8043
 8044        self.take_active_edit_prediction(cx);
 8045        let Some(provider) = self.edit_prediction_provider() else {
 8046            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8047            return None;
 8048        };
 8049
 8050        let (buffer, cursor_buffer_position) =
 8051            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8052
 8053        self.edit_prediction_settings =
 8054            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8055
 8056        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8057
 8058        if self.edit_prediction_indent_conflict {
 8059            let cursor_point = cursor.to_point(&multibuffer);
 8060
 8061            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 8062
 8063            if let Some((_, indent)) = indents.iter().next()
 8064                && indent.len == cursor_point.column
 8065            {
 8066                self.edit_prediction_indent_conflict = false;
 8067            }
 8068        }
 8069
 8070        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8071
 8072        let (completion_id, edits, edit_preview) = match edit_prediction {
 8073            edit_prediction::EditPrediction::Local {
 8074                id,
 8075                edits,
 8076                edit_preview,
 8077            } => (id, edits, edit_preview),
 8078            edit_prediction::EditPrediction::Jump {
 8079                id,
 8080                snapshot,
 8081                target,
 8082            } => {
 8083                self.stale_edit_prediction_in_menu = None;
 8084                self.active_edit_prediction = Some(EditPredictionState {
 8085                    inlay_ids: vec![],
 8086                    completion: EditPrediction::MoveOutside { snapshot, target },
 8087                    completion_id: id,
 8088                    invalidation_range: None,
 8089                });
 8090                cx.notify();
 8091                return Some(());
 8092            }
 8093        };
 8094
 8095        let edits = edits
 8096            .into_iter()
 8097            .flat_map(|(range, new_text)| {
 8098                Some((
 8099                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8100                    new_text,
 8101                ))
 8102            })
 8103            .collect::<Vec<_>>();
 8104        if edits.is_empty() {
 8105            return None;
 8106        }
 8107
 8108        let first_edit_start = edits.first().unwrap().0.start;
 8109        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8110        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8111
 8112        let last_edit_end = edits.last().unwrap().0.end;
 8113        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8114        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8115
 8116        let cursor_row = cursor.to_point(&multibuffer).row;
 8117
 8118        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8119
 8120        let mut inlay_ids = Vec::new();
 8121        let invalidation_row_range;
 8122        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8123            Some(cursor_row..edit_end_row)
 8124        } else if cursor_row > edit_end_row {
 8125            Some(edit_start_row..cursor_row)
 8126        } else {
 8127            None
 8128        };
 8129        let supports_jump = self
 8130            .edit_prediction_provider
 8131            .as_ref()
 8132            .map(|provider| provider.provider.supports_jump_to_edit())
 8133            .unwrap_or(true);
 8134
 8135        let is_move = supports_jump
 8136            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8137        let completion = if is_move {
 8138            invalidation_row_range =
 8139                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8140            let target = first_edit_start;
 8141            EditPrediction::MoveWithin { target, snapshot }
 8142        } else {
 8143            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8144                && !self.edit_predictions_hidden_for_vim_mode;
 8145
 8146            if show_completions_in_buffer {
 8147                if let Some(provider) = &self.edit_prediction_provider {
 8148                    provider.provider.did_show(cx);
 8149                }
 8150                if edits
 8151                    .iter()
 8152                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8153                {
 8154                    let mut inlays = Vec::new();
 8155                    for (range, new_text) in &edits {
 8156                        let inlay = Inlay::edit_prediction(
 8157                            post_inc(&mut self.next_inlay_id),
 8158                            range.start,
 8159                            new_text.as_ref(),
 8160                        );
 8161                        inlay_ids.push(inlay.id);
 8162                        inlays.push(inlay);
 8163                    }
 8164
 8165                    self.splice_inlays(&[], inlays, cx);
 8166                } else {
 8167                    let background_color = cx.theme().status().deleted_background;
 8168                    self.highlight_text::<EditPredictionHighlight>(
 8169                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8170                        HighlightStyle {
 8171                            background_color: Some(background_color),
 8172                            ..Default::default()
 8173                        },
 8174                        cx,
 8175                    );
 8176                }
 8177            }
 8178
 8179            invalidation_row_range = edit_start_row..edit_end_row;
 8180
 8181            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8182                if provider.show_tab_accept_marker() {
 8183                    EditDisplayMode::TabAccept
 8184                } else {
 8185                    EditDisplayMode::Inline
 8186                }
 8187            } else {
 8188                EditDisplayMode::DiffPopover
 8189            };
 8190
 8191            EditPrediction::Edit {
 8192                edits,
 8193                edit_preview,
 8194                display_mode,
 8195                snapshot,
 8196            }
 8197        };
 8198
 8199        let invalidation_range = multibuffer
 8200            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8201            ..multibuffer.anchor_after(Point::new(
 8202                invalidation_row_range.end,
 8203                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8204            ));
 8205
 8206        self.stale_edit_prediction_in_menu = None;
 8207        self.active_edit_prediction = Some(EditPredictionState {
 8208            inlay_ids,
 8209            completion,
 8210            completion_id,
 8211            invalidation_range: Some(invalidation_range),
 8212        });
 8213
 8214        cx.notify();
 8215
 8216        Some(())
 8217    }
 8218
 8219    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8220        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8221    }
 8222
 8223    fn clear_tasks(&mut self) {
 8224        self.tasks.clear()
 8225    }
 8226
 8227    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8228        if self.tasks.insert(key, value).is_some() {
 8229            // This case should hopefully be rare, but just in case...
 8230            log::error!(
 8231                "multiple different run targets found on a single line, only the last target will be rendered"
 8232            )
 8233        }
 8234    }
 8235
 8236    /// Get all display points of breakpoints that will be rendered within editor
 8237    ///
 8238    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8239    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8240    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8241    fn active_breakpoints(
 8242        &self,
 8243        range: Range<DisplayRow>,
 8244        window: &mut Window,
 8245        cx: &mut Context<Self>,
 8246    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8247        let mut breakpoint_display_points = HashMap::default();
 8248
 8249        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8250            return breakpoint_display_points;
 8251        };
 8252
 8253        let snapshot = self.snapshot(window, cx);
 8254
 8255        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8256        let Some(project) = self.project() else {
 8257            return breakpoint_display_points;
 8258        };
 8259
 8260        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8261            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8262
 8263        for (buffer_snapshot, range, excerpt_id) in
 8264            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8265        {
 8266            let Some(buffer) = project
 8267                .read(cx)
 8268                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8269            else {
 8270                continue;
 8271            };
 8272            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8273                &buffer,
 8274                Some(
 8275                    buffer_snapshot.anchor_before(range.start)
 8276                        ..buffer_snapshot.anchor_after(range.end),
 8277                ),
 8278                buffer_snapshot,
 8279                cx,
 8280            );
 8281            for (breakpoint, state) in breakpoints {
 8282                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8283                let position = multi_buffer_anchor
 8284                    .to_point(&multi_buffer_snapshot)
 8285                    .to_display_point(&snapshot);
 8286
 8287                breakpoint_display_points.insert(
 8288                    position.row(),
 8289                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8290                );
 8291            }
 8292        }
 8293
 8294        breakpoint_display_points
 8295    }
 8296
 8297    fn breakpoint_context_menu(
 8298        &self,
 8299        anchor: Anchor,
 8300        window: &mut Window,
 8301        cx: &mut Context<Self>,
 8302    ) -> Entity<ui::ContextMenu> {
 8303        let weak_editor = cx.weak_entity();
 8304        let focus_handle = self.focus_handle(cx);
 8305
 8306        let row = self
 8307            .buffer
 8308            .read(cx)
 8309            .snapshot(cx)
 8310            .summary_for_anchor::<Point>(&anchor)
 8311            .row;
 8312
 8313        let breakpoint = self
 8314            .breakpoint_at_row(row, window, cx)
 8315            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8316
 8317        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8318            "Edit Log Breakpoint"
 8319        } else {
 8320            "Set Log Breakpoint"
 8321        };
 8322
 8323        let condition_breakpoint_msg = if breakpoint
 8324            .as_ref()
 8325            .is_some_and(|bp| bp.1.condition.is_some())
 8326        {
 8327            "Edit Condition Breakpoint"
 8328        } else {
 8329            "Set Condition Breakpoint"
 8330        };
 8331
 8332        let hit_condition_breakpoint_msg = if breakpoint
 8333            .as_ref()
 8334            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8335        {
 8336            "Edit Hit Condition Breakpoint"
 8337        } else {
 8338            "Set Hit Condition Breakpoint"
 8339        };
 8340
 8341        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8342            "Unset Breakpoint"
 8343        } else {
 8344            "Set Breakpoint"
 8345        };
 8346
 8347        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8348
 8349        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8350            BreakpointState::Enabled => Some("Disable"),
 8351            BreakpointState::Disabled => Some("Enable"),
 8352        });
 8353
 8354        let (anchor, breakpoint) =
 8355            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8356
 8357        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8358            menu.on_blur_subscription(Subscription::new(|| {}))
 8359                .context(focus_handle)
 8360                .when(run_to_cursor, |this| {
 8361                    let weak_editor = weak_editor.clone();
 8362                    this.entry("Run to cursor", None, move |window, cx| {
 8363                        weak_editor
 8364                            .update(cx, |editor, cx| {
 8365                                editor.change_selections(
 8366                                    SelectionEffects::no_scroll(),
 8367                                    window,
 8368                                    cx,
 8369                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8370                                );
 8371                            })
 8372                            .ok();
 8373
 8374                        window.dispatch_action(Box::new(RunToCursor), cx);
 8375                    })
 8376                    .separator()
 8377                })
 8378                .when_some(toggle_state_msg, |this, msg| {
 8379                    this.entry(msg, None, {
 8380                        let weak_editor = weak_editor.clone();
 8381                        let breakpoint = breakpoint.clone();
 8382                        move |_window, cx| {
 8383                            weak_editor
 8384                                .update(cx, |this, cx| {
 8385                                    this.edit_breakpoint_at_anchor(
 8386                                        anchor,
 8387                                        breakpoint.as_ref().clone(),
 8388                                        BreakpointEditAction::InvertState,
 8389                                        cx,
 8390                                    );
 8391                                })
 8392                                .log_err();
 8393                        }
 8394                    })
 8395                })
 8396                .entry(set_breakpoint_msg, None, {
 8397                    let weak_editor = weak_editor.clone();
 8398                    let breakpoint = breakpoint.clone();
 8399                    move |_window, cx| {
 8400                        weak_editor
 8401                            .update(cx, |this, cx| {
 8402                                this.edit_breakpoint_at_anchor(
 8403                                    anchor,
 8404                                    breakpoint.as_ref().clone(),
 8405                                    BreakpointEditAction::Toggle,
 8406                                    cx,
 8407                                );
 8408                            })
 8409                            .log_err();
 8410                    }
 8411                })
 8412                .entry(log_breakpoint_msg, None, {
 8413                    let breakpoint = breakpoint.clone();
 8414                    let weak_editor = weak_editor.clone();
 8415                    move |window, cx| {
 8416                        weak_editor
 8417                            .update(cx, |this, cx| {
 8418                                this.add_edit_breakpoint_block(
 8419                                    anchor,
 8420                                    breakpoint.as_ref(),
 8421                                    BreakpointPromptEditAction::Log,
 8422                                    window,
 8423                                    cx,
 8424                                );
 8425                            })
 8426                            .log_err();
 8427                    }
 8428                })
 8429                .entry(condition_breakpoint_msg, None, {
 8430                    let breakpoint = breakpoint.clone();
 8431                    let weak_editor = weak_editor.clone();
 8432                    move |window, cx| {
 8433                        weak_editor
 8434                            .update(cx, |this, cx| {
 8435                                this.add_edit_breakpoint_block(
 8436                                    anchor,
 8437                                    breakpoint.as_ref(),
 8438                                    BreakpointPromptEditAction::Condition,
 8439                                    window,
 8440                                    cx,
 8441                                );
 8442                            })
 8443                            .log_err();
 8444                    }
 8445                })
 8446                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8447                    weak_editor
 8448                        .update(cx, |this, cx| {
 8449                            this.add_edit_breakpoint_block(
 8450                                anchor,
 8451                                breakpoint.as_ref(),
 8452                                BreakpointPromptEditAction::HitCondition,
 8453                                window,
 8454                                cx,
 8455                            );
 8456                        })
 8457                        .log_err();
 8458                })
 8459        })
 8460    }
 8461
 8462    fn render_breakpoint(
 8463        &self,
 8464        position: Anchor,
 8465        row: DisplayRow,
 8466        breakpoint: &Breakpoint,
 8467        state: Option<BreakpointSessionState>,
 8468        cx: &mut Context<Self>,
 8469    ) -> IconButton {
 8470        let is_rejected = state.is_some_and(|s| !s.verified);
 8471        // Is it a breakpoint that shows up when hovering over gutter?
 8472        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8473            (false, false),
 8474            |PhantomBreakpointIndicator {
 8475                 is_active,
 8476                 display_row,
 8477                 collides_with_existing_breakpoint,
 8478             }| {
 8479                (
 8480                    is_active && display_row == row,
 8481                    collides_with_existing_breakpoint,
 8482                )
 8483            },
 8484        );
 8485
 8486        let (color, icon) = {
 8487            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8488                (false, false) => ui::IconName::DebugBreakpoint,
 8489                (true, false) => ui::IconName::DebugLogBreakpoint,
 8490                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8491                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8492            };
 8493
 8494            let color = cx.theme().colors();
 8495
 8496            let color = if is_phantom {
 8497                if collides_with_existing {
 8498                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8499                } else {
 8500                    Color::Hint
 8501                }
 8502            } else if is_rejected {
 8503                Color::Disabled
 8504            } else {
 8505                Color::Debugger
 8506            };
 8507
 8508            (color, icon)
 8509        };
 8510
 8511        let breakpoint = Arc::from(breakpoint.clone());
 8512
 8513        let alt_as_text = gpui::Keystroke {
 8514            modifiers: Modifiers::secondary_key(),
 8515            ..Default::default()
 8516        };
 8517        let primary_action_text = if breakpoint.is_disabled() {
 8518            "Enable breakpoint"
 8519        } else if is_phantom && !collides_with_existing {
 8520            "Set breakpoint"
 8521        } else {
 8522            "Unset breakpoint"
 8523        };
 8524        let focus_handle = self.focus_handle.clone();
 8525
 8526        let meta = if is_rejected {
 8527            SharedString::from("No executable code is associated with this line.")
 8528        } else if collides_with_existing && !breakpoint.is_disabled() {
 8529            SharedString::from(format!(
 8530                "{alt_as_text}-click to disable,\nright-click for more options."
 8531            ))
 8532        } else {
 8533            SharedString::from("Right-click for more options.")
 8534        };
 8535        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8536            .icon_size(IconSize::XSmall)
 8537            .size(ui::ButtonSize::None)
 8538            .when(is_rejected, |this| {
 8539                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8540            })
 8541            .icon_color(color)
 8542            .style(ButtonStyle::Transparent)
 8543            .on_click(cx.listener({
 8544                move |editor, event: &ClickEvent, window, cx| {
 8545                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8546                        BreakpointEditAction::InvertState
 8547                    } else {
 8548                        BreakpointEditAction::Toggle
 8549                    };
 8550
 8551                    window.focus(&editor.focus_handle(cx));
 8552                    editor.edit_breakpoint_at_anchor(
 8553                        position,
 8554                        breakpoint.as_ref().clone(),
 8555                        edit_action,
 8556                        cx,
 8557                    );
 8558                }
 8559            }))
 8560            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8561                editor.set_breakpoint_context_menu(
 8562                    row,
 8563                    Some(position),
 8564                    event.position(),
 8565                    window,
 8566                    cx,
 8567                );
 8568            }))
 8569            .tooltip(move |_window, cx| {
 8570                Tooltip::with_meta_in(
 8571                    primary_action_text,
 8572                    Some(&ToggleBreakpoint),
 8573                    meta.clone(),
 8574                    &focus_handle,
 8575                    cx,
 8576                )
 8577            })
 8578    }
 8579
 8580    fn build_tasks_context(
 8581        project: &Entity<Project>,
 8582        buffer: &Entity<Buffer>,
 8583        buffer_row: u32,
 8584        tasks: &Arc<RunnableTasks>,
 8585        cx: &mut Context<Self>,
 8586    ) -> Task<Option<task::TaskContext>> {
 8587        let position = Point::new(buffer_row, tasks.column);
 8588        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8589        let location = Location {
 8590            buffer: buffer.clone(),
 8591            range: range_start..range_start,
 8592        };
 8593        // Fill in the environmental variables from the tree-sitter captures
 8594        let mut captured_task_variables = TaskVariables::default();
 8595        for (capture_name, value) in tasks.extra_variables.clone() {
 8596            captured_task_variables.insert(
 8597                task::VariableName::Custom(capture_name.into()),
 8598                value.clone(),
 8599            );
 8600        }
 8601        project.update(cx, |project, cx| {
 8602            project.task_store().update(cx, |task_store, cx| {
 8603                task_store.task_context_for_location(captured_task_variables, location, cx)
 8604            })
 8605        })
 8606    }
 8607
 8608    pub fn spawn_nearest_task(
 8609        &mut self,
 8610        action: &SpawnNearestTask,
 8611        window: &mut Window,
 8612        cx: &mut Context<Self>,
 8613    ) {
 8614        let Some((workspace, _)) = self.workspace.clone() else {
 8615            return;
 8616        };
 8617        let Some(project) = self.project.clone() else {
 8618            return;
 8619        };
 8620
 8621        // Try to find a closest, enclosing node using tree-sitter that has a task
 8622        let Some((buffer, buffer_row, tasks)) = self
 8623            .find_enclosing_node_task(cx)
 8624            // Or find the task that's closest in row-distance.
 8625            .or_else(|| self.find_closest_task(cx))
 8626        else {
 8627            return;
 8628        };
 8629
 8630        let reveal_strategy = action.reveal;
 8631        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8632        cx.spawn_in(window, async move |_, cx| {
 8633            let context = task_context.await?;
 8634            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8635
 8636            let resolved = &mut resolved_task.resolved;
 8637            resolved.reveal = reveal_strategy;
 8638
 8639            workspace
 8640                .update_in(cx, |workspace, window, cx| {
 8641                    workspace.schedule_resolved_task(
 8642                        task_source_kind,
 8643                        resolved_task,
 8644                        false,
 8645                        window,
 8646                        cx,
 8647                    );
 8648                })
 8649                .ok()
 8650        })
 8651        .detach();
 8652    }
 8653
 8654    fn find_closest_task(
 8655        &mut self,
 8656        cx: &mut Context<Self>,
 8657    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8658        let cursor_row = self
 8659            .selections
 8660            .newest_adjusted(&self.display_snapshot(cx))
 8661            .head()
 8662            .row;
 8663
 8664        let ((buffer_id, row), tasks) = self
 8665            .tasks
 8666            .iter()
 8667            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8668
 8669        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8670        let tasks = Arc::new(tasks.to_owned());
 8671        Some((buffer, *row, tasks))
 8672    }
 8673
 8674    fn find_enclosing_node_task(
 8675        &mut self,
 8676        cx: &mut Context<Self>,
 8677    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8678        let snapshot = self.buffer.read(cx).snapshot(cx);
 8679        let offset = self
 8680            .selections
 8681            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8682            .head();
 8683        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8684        let offset = excerpt.map_offset_to_buffer(offset);
 8685        let buffer_id = excerpt.buffer().remote_id();
 8686
 8687        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8688        let mut cursor = layer.node().walk();
 8689
 8690        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8691            if cursor.node().end_byte() == offset.0 {
 8692                cursor.goto_next_sibling();
 8693            }
 8694        }
 8695
 8696        // Ascend to the smallest ancestor that contains the range and has a task.
 8697        loop {
 8698            let node = cursor.node();
 8699            let node_range = node.byte_range();
 8700            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8701
 8702            // Check if this node contains our offset
 8703            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8704                // If it contains offset, check for task
 8705                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8706                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8707                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8708                }
 8709            }
 8710
 8711            if !cursor.goto_parent() {
 8712                break;
 8713            }
 8714        }
 8715        None
 8716    }
 8717
 8718    fn render_run_indicator(
 8719        &self,
 8720        _style: &EditorStyle,
 8721        is_active: bool,
 8722        row: DisplayRow,
 8723        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8724        cx: &mut Context<Self>,
 8725    ) -> IconButton {
 8726        let color = Color::Muted;
 8727        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8728
 8729        IconButton::new(
 8730            ("run_indicator", row.0 as usize),
 8731            ui::IconName::PlayOutlined,
 8732        )
 8733        .shape(ui::IconButtonShape::Square)
 8734        .icon_size(IconSize::XSmall)
 8735        .icon_color(color)
 8736        .toggle_state(is_active)
 8737        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8738            let quick_launch = match e {
 8739                ClickEvent::Keyboard(_) => true,
 8740                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8741            };
 8742
 8743            window.focus(&editor.focus_handle(cx));
 8744            editor.toggle_code_actions(
 8745                &ToggleCodeActions {
 8746                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8747                    quick_launch,
 8748                },
 8749                window,
 8750                cx,
 8751            );
 8752        }))
 8753        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8754            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8755        }))
 8756    }
 8757
 8758    pub fn context_menu_visible(&self) -> bool {
 8759        !self.edit_prediction_preview_is_active()
 8760            && self
 8761                .context_menu
 8762                .borrow()
 8763                .as_ref()
 8764                .is_some_and(|menu| menu.visible())
 8765    }
 8766
 8767    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8768        self.context_menu
 8769            .borrow()
 8770            .as_ref()
 8771            .map(|menu| menu.origin())
 8772    }
 8773
 8774    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8775        self.context_menu_options = Some(options);
 8776    }
 8777
 8778    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8779    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8780
 8781    fn render_edit_prediction_popover(
 8782        &mut self,
 8783        text_bounds: &Bounds<Pixels>,
 8784        content_origin: gpui::Point<Pixels>,
 8785        right_margin: Pixels,
 8786        editor_snapshot: &EditorSnapshot,
 8787        visible_row_range: Range<DisplayRow>,
 8788        scroll_top: ScrollOffset,
 8789        scroll_bottom: ScrollOffset,
 8790        line_layouts: &[LineWithInvisibles],
 8791        line_height: Pixels,
 8792        scroll_position: gpui::Point<ScrollOffset>,
 8793        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8794        newest_selection_head: Option<DisplayPoint>,
 8795        editor_width: Pixels,
 8796        style: &EditorStyle,
 8797        window: &mut Window,
 8798        cx: &mut App,
 8799    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8800        if self.mode().is_minimap() {
 8801            return None;
 8802        }
 8803        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8804
 8805        if self.edit_prediction_visible_in_cursor_popover(true) {
 8806            return None;
 8807        }
 8808
 8809        match &active_edit_prediction.completion {
 8810            EditPrediction::MoveWithin { target, .. } => {
 8811                let target_display_point = target.to_display_point(editor_snapshot);
 8812
 8813                if self.edit_prediction_requires_modifier() {
 8814                    if !self.edit_prediction_preview_is_active() {
 8815                        return None;
 8816                    }
 8817
 8818                    self.render_edit_prediction_modifier_jump_popover(
 8819                        text_bounds,
 8820                        content_origin,
 8821                        visible_row_range,
 8822                        line_layouts,
 8823                        line_height,
 8824                        scroll_pixel_position,
 8825                        newest_selection_head,
 8826                        target_display_point,
 8827                        window,
 8828                        cx,
 8829                    )
 8830                } else {
 8831                    self.render_edit_prediction_eager_jump_popover(
 8832                        text_bounds,
 8833                        content_origin,
 8834                        editor_snapshot,
 8835                        visible_row_range,
 8836                        scroll_top,
 8837                        scroll_bottom,
 8838                        line_height,
 8839                        scroll_pixel_position,
 8840                        target_display_point,
 8841                        editor_width,
 8842                        window,
 8843                        cx,
 8844                    )
 8845                }
 8846            }
 8847            EditPrediction::Edit {
 8848                display_mode: EditDisplayMode::Inline,
 8849                ..
 8850            } => None,
 8851            EditPrediction::Edit {
 8852                display_mode: EditDisplayMode::TabAccept,
 8853                edits,
 8854                ..
 8855            } => {
 8856                let range = &edits.first()?.0;
 8857                let target_display_point = range.end.to_display_point(editor_snapshot);
 8858
 8859                self.render_edit_prediction_end_of_line_popover(
 8860                    "Accept",
 8861                    editor_snapshot,
 8862                    visible_row_range,
 8863                    target_display_point,
 8864                    line_height,
 8865                    scroll_pixel_position,
 8866                    content_origin,
 8867                    editor_width,
 8868                    window,
 8869                    cx,
 8870                )
 8871            }
 8872            EditPrediction::Edit {
 8873                edits,
 8874                edit_preview,
 8875                display_mode: EditDisplayMode::DiffPopover,
 8876                snapshot,
 8877            } => self.render_edit_prediction_diff_popover(
 8878                text_bounds,
 8879                content_origin,
 8880                right_margin,
 8881                editor_snapshot,
 8882                visible_row_range,
 8883                line_layouts,
 8884                line_height,
 8885                scroll_position,
 8886                scroll_pixel_position,
 8887                newest_selection_head,
 8888                editor_width,
 8889                style,
 8890                edits,
 8891                edit_preview,
 8892                snapshot,
 8893                window,
 8894                cx,
 8895            ),
 8896            EditPrediction::MoveOutside { snapshot, .. } => {
 8897                let mut element = self
 8898                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8899                    .into_any();
 8900
 8901                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8902                let origin_x = text_bounds.size.width - size.width - px(30.);
 8903                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8904                element.prepaint_at(origin, window, cx);
 8905
 8906                Some((element, origin))
 8907            }
 8908        }
 8909    }
 8910
 8911    fn render_edit_prediction_modifier_jump_popover(
 8912        &mut self,
 8913        text_bounds: &Bounds<Pixels>,
 8914        content_origin: gpui::Point<Pixels>,
 8915        visible_row_range: Range<DisplayRow>,
 8916        line_layouts: &[LineWithInvisibles],
 8917        line_height: Pixels,
 8918        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8919        newest_selection_head: Option<DisplayPoint>,
 8920        target_display_point: DisplayPoint,
 8921        window: &mut Window,
 8922        cx: &mut App,
 8923    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8924        let scrolled_content_origin =
 8925            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8926
 8927        const SCROLL_PADDING_Y: Pixels = px(12.);
 8928
 8929        if target_display_point.row() < visible_row_range.start {
 8930            return self.render_edit_prediction_scroll_popover(
 8931                |_| SCROLL_PADDING_Y,
 8932                IconName::ArrowUp,
 8933                visible_row_range,
 8934                line_layouts,
 8935                newest_selection_head,
 8936                scrolled_content_origin,
 8937                window,
 8938                cx,
 8939            );
 8940        } else if target_display_point.row() >= visible_row_range.end {
 8941            return self.render_edit_prediction_scroll_popover(
 8942                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8943                IconName::ArrowDown,
 8944                visible_row_range,
 8945                line_layouts,
 8946                newest_selection_head,
 8947                scrolled_content_origin,
 8948                window,
 8949                cx,
 8950            );
 8951        }
 8952
 8953        const POLE_WIDTH: Pixels = px(2.);
 8954
 8955        let line_layout =
 8956            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8957        let target_column = target_display_point.column() as usize;
 8958
 8959        let target_x = line_layout.x_for_index(target_column);
 8960        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8961            - scroll_pixel_position.y;
 8962
 8963        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8964
 8965        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8966        border_color.l += 0.001;
 8967
 8968        let mut element = v_flex()
 8969            .items_end()
 8970            .when(flag_on_right, |el| el.items_start())
 8971            .child(if flag_on_right {
 8972                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8973                    .rounded_bl(px(0.))
 8974                    .rounded_tl(px(0.))
 8975                    .border_l_2()
 8976                    .border_color(border_color)
 8977            } else {
 8978                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8979                    .rounded_br(px(0.))
 8980                    .rounded_tr(px(0.))
 8981                    .border_r_2()
 8982                    .border_color(border_color)
 8983            })
 8984            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8985            .into_any();
 8986
 8987        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8988
 8989        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8990            - point(
 8991                if flag_on_right {
 8992                    POLE_WIDTH
 8993                } else {
 8994                    size.width - POLE_WIDTH
 8995                },
 8996                size.height - line_height,
 8997            );
 8998
 8999        origin.x = origin.x.max(content_origin.x);
 9000
 9001        element.prepaint_at(origin, window, cx);
 9002
 9003        Some((element, origin))
 9004    }
 9005
 9006    fn render_edit_prediction_scroll_popover(
 9007        &mut self,
 9008        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9009        scroll_icon: IconName,
 9010        visible_row_range: Range<DisplayRow>,
 9011        line_layouts: &[LineWithInvisibles],
 9012        newest_selection_head: Option<DisplayPoint>,
 9013        scrolled_content_origin: gpui::Point<Pixels>,
 9014        window: &mut Window,
 9015        cx: &mut App,
 9016    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9017        let mut element = self
 9018            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9019            .into_any();
 9020
 9021        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9022
 9023        let cursor = newest_selection_head?;
 9024        let cursor_row_layout =
 9025            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9026        let cursor_column = cursor.column() as usize;
 9027
 9028        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9029
 9030        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9031
 9032        element.prepaint_at(origin, window, cx);
 9033        Some((element, origin))
 9034    }
 9035
 9036    fn render_edit_prediction_eager_jump_popover(
 9037        &mut self,
 9038        text_bounds: &Bounds<Pixels>,
 9039        content_origin: gpui::Point<Pixels>,
 9040        editor_snapshot: &EditorSnapshot,
 9041        visible_row_range: Range<DisplayRow>,
 9042        scroll_top: ScrollOffset,
 9043        scroll_bottom: ScrollOffset,
 9044        line_height: Pixels,
 9045        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9046        target_display_point: DisplayPoint,
 9047        editor_width: Pixels,
 9048        window: &mut Window,
 9049        cx: &mut App,
 9050    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9051        if target_display_point.row().as_f64() < scroll_top {
 9052            let mut element = self
 9053                .render_edit_prediction_line_popover(
 9054                    "Jump to Edit",
 9055                    Some(IconName::ArrowUp),
 9056                    window,
 9057                    cx,
 9058                )
 9059                .into_any();
 9060
 9061            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9062            let offset = point(
 9063                (text_bounds.size.width - size.width) / 2.,
 9064                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9065            );
 9066
 9067            let origin = text_bounds.origin + offset;
 9068            element.prepaint_at(origin, window, cx);
 9069            Some((element, origin))
 9070        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9071            let mut element = self
 9072                .render_edit_prediction_line_popover(
 9073                    "Jump to Edit",
 9074                    Some(IconName::ArrowDown),
 9075                    window,
 9076                    cx,
 9077                )
 9078                .into_any();
 9079
 9080            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9081            let offset = point(
 9082                (text_bounds.size.width - size.width) / 2.,
 9083                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9084            );
 9085
 9086            let origin = text_bounds.origin + offset;
 9087            element.prepaint_at(origin, window, cx);
 9088            Some((element, origin))
 9089        } else {
 9090            self.render_edit_prediction_end_of_line_popover(
 9091                "Jump to Edit",
 9092                editor_snapshot,
 9093                visible_row_range,
 9094                target_display_point,
 9095                line_height,
 9096                scroll_pixel_position,
 9097                content_origin,
 9098                editor_width,
 9099                window,
 9100                cx,
 9101            )
 9102        }
 9103    }
 9104
 9105    fn render_edit_prediction_end_of_line_popover(
 9106        self: &mut Editor,
 9107        label: &'static str,
 9108        editor_snapshot: &EditorSnapshot,
 9109        visible_row_range: Range<DisplayRow>,
 9110        target_display_point: DisplayPoint,
 9111        line_height: Pixels,
 9112        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9113        content_origin: gpui::Point<Pixels>,
 9114        editor_width: Pixels,
 9115        window: &mut Window,
 9116        cx: &mut App,
 9117    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9118        let target_line_end = DisplayPoint::new(
 9119            target_display_point.row(),
 9120            editor_snapshot.line_len(target_display_point.row()),
 9121        );
 9122
 9123        let mut element = self
 9124            .render_edit_prediction_line_popover(label, None, window, cx)
 9125            .into_any();
 9126
 9127        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9128
 9129        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9130
 9131        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9132        let mut origin = start_point
 9133            + line_origin
 9134            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9135        origin.x = origin.x.max(content_origin.x);
 9136
 9137        let max_x = content_origin.x + editor_width - size.width;
 9138
 9139        if origin.x > max_x {
 9140            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9141
 9142            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9143                origin.y += offset;
 9144                IconName::ArrowUp
 9145            } else {
 9146                origin.y -= offset;
 9147                IconName::ArrowDown
 9148            };
 9149
 9150            element = self
 9151                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9152                .into_any();
 9153
 9154            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9155
 9156            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9157        }
 9158
 9159        element.prepaint_at(origin, window, cx);
 9160        Some((element, origin))
 9161    }
 9162
 9163    fn render_edit_prediction_diff_popover(
 9164        self: &Editor,
 9165        text_bounds: &Bounds<Pixels>,
 9166        content_origin: gpui::Point<Pixels>,
 9167        right_margin: Pixels,
 9168        editor_snapshot: &EditorSnapshot,
 9169        visible_row_range: Range<DisplayRow>,
 9170        line_layouts: &[LineWithInvisibles],
 9171        line_height: Pixels,
 9172        scroll_position: gpui::Point<ScrollOffset>,
 9173        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9174        newest_selection_head: Option<DisplayPoint>,
 9175        editor_width: Pixels,
 9176        style: &EditorStyle,
 9177        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9178        edit_preview: &Option<language::EditPreview>,
 9179        snapshot: &language::BufferSnapshot,
 9180        window: &mut Window,
 9181        cx: &mut App,
 9182    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9183        let edit_start = edits
 9184            .first()
 9185            .unwrap()
 9186            .0
 9187            .start
 9188            .to_display_point(editor_snapshot);
 9189        let edit_end = edits
 9190            .last()
 9191            .unwrap()
 9192            .0
 9193            .end
 9194            .to_display_point(editor_snapshot);
 9195
 9196        let is_visible = visible_row_range.contains(&edit_start.row())
 9197            || visible_row_range.contains(&edit_end.row());
 9198        if !is_visible {
 9199            return None;
 9200        }
 9201
 9202        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9203            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9204        } else {
 9205            // Fallback for providers without edit_preview
 9206            crate::edit_prediction_fallback_text(edits, cx)
 9207        };
 9208
 9209        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9210        let line_count = highlighted_edits.text.lines().count();
 9211
 9212        const BORDER_WIDTH: Pixels = px(1.);
 9213
 9214        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9215        let has_keybind = keybind.is_some();
 9216
 9217        let mut element = h_flex()
 9218            .items_start()
 9219            .child(
 9220                h_flex()
 9221                    .bg(cx.theme().colors().editor_background)
 9222                    .border(BORDER_WIDTH)
 9223                    .shadow_xs()
 9224                    .border_color(cx.theme().colors().border)
 9225                    .rounded_l_lg()
 9226                    .when(line_count > 1, |el| el.rounded_br_lg())
 9227                    .pr_1()
 9228                    .child(styled_text),
 9229            )
 9230            .child(
 9231                h_flex()
 9232                    .h(line_height + BORDER_WIDTH * 2.)
 9233                    .px_1p5()
 9234                    .gap_1()
 9235                    // Workaround: For some reason, there's a gap if we don't do this
 9236                    .ml(-BORDER_WIDTH)
 9237                    .shadow(vec![gpui::BoxShadow {
 9238                        color: gpui::black().opacity(0.05),
 9239                        offset: point(px(1.), px(1.)),
 9240                        blur_radius: px(2.),
 9241                        spread_radius: px(0.),
 9242                    }])
 9243                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9244                    .border(BORDER_WIDTH)
 9245                    .border_color(cx.theme().colors().border)
 9246                    .rounded_r_lg()
 9247                    .id("edit_prediction_diff_popover_keybind")
 9248                    .when(!has_keybind, |el| {
 9249                        let status_colors = cx.theme().status();
 9250
 9251                        el.bg(status_colors.error_background)
 9252                            .border_color(status_colors.error.opacity(0.6))
 9253                            .child(Icon::new(IconName::Info).color(Color::Error))
 9254                            .cursor_default()
 9255                            .hoverable_tooltip(move |_window, cx| {
 9256                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9257                            })
 9258                    })
 9259                    .children(keybind),
 9260            )
 9261            .into_any();
 9262
 9263        let longest_row =
 9264            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9265        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9266            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9267        } else {
 9268            layout_line(
 9269                longest_row,
 9270                editor_snapshot,
 9271                style,
 9272                editor_width,
 9273                |_| false,
 9274                window,
 9275                cx,
 9276            )
 9277            .width
 9278        };
 9279
 9280        let viewport_bounds =
 9281            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9282                right: -right_margin,
 9283                ..Default::default()
 9284            });
 9285
 9286        let x_after_longest = Pixels::from(
 9287            ScrollPixelOffset::from(
 9288                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9289            ) - scroll_pixel_position.x,
 9290        );
 9291
 9292        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9293
 9294        // Fully visible if it can be displayed within the window (allow overlapping other
 9295        // panes). However, this is only allowed if the popover starts within text_bounds.
 9296        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9297            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9298
 9299        let mut origin = if can_position_to_the_right {
 9300            point(
 9301                x_after_longest,
 9302                text_bounds.origin.y
 9303                    + Pixels::from(
 9304                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9305                            - scroll_pixel_position.y,
 9306                    ),
 9307            )
 9308        } else {
 9309            let cursor_row = newest_selection_head.map(|head| head.row());
 9310            let above_edit = edit_start
 9311                .row()
 9312                .0
 9313                .checked_sub(line_count as u32)
 9314                .map(DisplayRow);
 9315            let below_edit = Some(edit_end.row() + 1);
 9316            let above_cursor =
 9317                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9318            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9319
 9320            // Place the edit popover adjacent to the edit if there is a location
 9321            // available that is onscreen and does not obscure the cursor. Otherwise,
 9322            // place it adjacent to the cursor.
 9323            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9324                .into_iter()
 9325                .flatten()
 9326                .find(|&start_row| {
 9327                    let end_row = start_row + line_count as u32;
 9328                    visible_row_range.contains(&start_row)
 9329                        && visible_row_range.contains(&end_row)
 9330                        && cursor_row
 9331                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9332                })?;
 9333
 9334            content_origin
 9335                + point(
 9336                    Pixels::from(-scroll_pixel_position.x),
 9337                    Pixels::from(
 9338                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9339                    ),
 9340                )
 9341        };
 9342
 9343        origin.x -= BORDER_WIDTH;
 9344
 9345        window.defer_draw(element, origin, 1);
 9346
 9347        // Do not return an element, since it will already be drawn due to defer_draw.
 9348        None
 9349    }
 9350
 9351    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9352        px(30.)
 9353    }
 9354
 9355    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9356        if self.read_only(cx) {
 9357            cx.theme().players().read_only()
 9358        } else {
 9359            self.style.as_ref().unwrap().local_player
 9360        }
 9361    }
 9362
 9363    fn render_edit_prediction_accept_keybind(
 9364        &self,
 9365        window: &mut Window,
 9366        cx: &mut App,
 9367    ) -> Option<AnyElement> {
 9368        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9369        let accept_keystroke = accept_binding.keystroke()?;
 9370
 9371        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9372
 9373        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9374            Color::Accent
 9375        } else {
 9376            Color::Muted
 9377        };
 9378
 9379        h_flex()
 9380            .px_0p5()
 9381            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9382            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9383            .text_size(TextSize::XSmall.rems(cx))
 9384            .child(h_flex().children(ui::render_modifiers(
 9385                accept_keystroke.modifiers(),
 9386                PlatformStyle::platform(),
 9387                Some(modifiers_color),
 9388                Some(IconSize::XSmall.rems().into()),
 9389                true,
 9390            )))
 9391            .when(is_platform_style_mac, |parent| {
 9392                parent.child(accept_keystroke.key().to_string())
 9393            })
 9394            .when(!is_platform_style_mac, |parent| {
 9395                parent.child(
 9396                    Key::new(
 9397                        util::capitalize(accept_keystroke.key()),
 9398                        Some(Color::Default),
 9399                    )
 9400                    .size(Some(IconSize::XSmall.rems().into())),
 9401                )
 9402            })
 9403            .into_any()
 9404            .into()
 9405    }
 9406
 9407    fn render_edit_prediction_line_popover(
 9408        &self,
 9409        label: impl Into<SharedString>,
 9410        icon: Option<IconName>,
 9411        window: &mut Window,
 9412        cx: &mut App,
 9413    ) -> Stateful<Div> {
 9414        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9415
 9416        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9417        let has_keybind = keybind.is_some();
 9418
 9419        h_flex()
 9420            .id("ep-line-popover")
 9421            .py_0p5()
 9422            .pl_1()
 9423            .pr(padding_right)
 9424            .gap_1()
 9425            .rounded_md()
 9426            .border_1()
 9427            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9428            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9429            .shadow_xs()
 9430            .when(!has_keybind, |el| {
 9431                let status_colors = cx.theme().status();
 9432
 9433                el.bg(status_colors.error_background)
 9434                    .border_color(status_colors.error.opacity(0.6))
 9435                    .pl_2()
 9436                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9437                    .cursor_default()
 9438                    .hoverable_tooltip(move |_window, cx| {
 9439                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9440                    })
 9441            })
 9442            .children(keybind)
 9443            .child(
 9444                Label::new(label)
 9445                    .size(LabelSize::Small)
 9446                    .when(!has_keybind, |el| {
 9447                        el.color(cx.theme().status().error.into()).strikethrough()
 9448                    }),
 9449            )
 9450            .when(!has_keybind, |el| {
 9451                el.child(
 9452                    h_flex().ml_1().child(
 9453                        Icon::new(IconName::Info)
 9454                            .size(IconSize::Small)
 9455                            .color(cx.theme().status().error.into()),
 9456                    ),
 9457                )
 9458            })
 9459            .when_some(icon, |element, icon| {
 9460                element.child(
 9461                    div()
 9462                        .mt(px(1.5))
 9463                        .child(Icon::new(icon).size(IconSize::Small)),
 9464                )
 9465            })
 9466    }
 9467
 9468    fn render_edit_prediction_jump_outside_popover(
 9469        &self,
 9470        snapshot: &BufferSnapshot,
 9471        window: &mut Window,
 9472        cx: &mut App,
 9473    ) -> Stateful<Div> {
 9474        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9475        let has_keybind = keybind.is_some();
 9476
 9477        let file_name = snapshot
 9478            .file()
 9479            .map(|file| SharedString::new(file.file_name(cx)))
 9480            .unwrap_or(SharedString::new_static("untitled"));
 9481
 9482        h_flex()
 9483            .id("ep-jump-outside-popover")
 9484            .py_1()
 9485            .px_2()
 9486            .gap_1()
 9487            .rounded_md()
 9488            .border_1()
 9489            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9490            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9491            .shadow_xs()
 9492            .when(!has_keybind, |el| {
 9493                let status_colors = cx.theme().status();
 9494
 9495                el.bg(status_colors.error_background)
 9496                    .border_color(status_colors.error.opacity(0.6))
 9497                    .pl_2()
 9498                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9499                    .cursor_default()
 9500                    .hoverable_tooltip(move |_window, cx| {
 9501                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9502                    })
 9503            })
 9504            .children(keybind)
 9505            .child(
 9506                Label::new(file_name)
 9507                    .size(LabelSize::Small)
 9508                    .buffer_font(cx)
 9509                    .when(!has_keybind, |el| {
 9510                        el.color(cx.theme().status().error.into()).strikethrough()
 9511                    }),
 9512            )
 9513            .when(!has_keybind, |el| {
 9514                el.child(
 9515                    h_flex().ml_1().child(
 9516                        Icon::new(IconName::Info)
 9517                            .size(IconSize::Small)
 9518                            .color(cx.theme().status().error.into()),
 9519                    ),
 9520                )
 9521            })
 9522            .child(
 9523                div()
 9524                    .mt(px(1.5))
 9525                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9526            )
 9527    }
 9528
 9529    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9530        let accent_color = cx.theme().colors().text_accent;
 9531        let editor_bg_color = cx.theme().colors().editor_background;
 9532        editor_bg_color.blend(accent_color.opacity(0.1))
 9533    }
 9534
 9535    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9536        let accent_color = cx.theme().colors().text_accent;
 9537        let editor_bg_color = cx.theme().colors().editor_background;
 9538        editor_bg_color.blend(accent_color.opacity(0.6))
 9539    }
 9540    fn get_prediction_provider_icon_name(
 9541        provider: &Option<RegisteredEditPredictionProvider>,
 9542    ) -> IconName {
 9543        match provider {
 9544            Some(provider) => match provider.provider.name() {
 9545                "copilot" => IconName::Copilot,
 9546                "supermaven" => IconName::Supermaven,
 9547                _ => IconName::ZedPredict,
 9548            },
 9549            None => IconName::ZedPredict,
 9550        }
 9551    }
 9552
 9553    fn render_edit_prediction_cursor_popover(
 9554        &self,
 9555        min_width: Pixels,
 9556        max_width: Pixels,
 9557        cursor_point: Point,
 9558        style: &EditorStyle,
 9559        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9560        _window: &Window,
 9561        cx: &mut Context<Editor>,
 9562    ) -> Option<AnyElement> {
 9563        let provider = self.edit_prediction_provider.as_ref()?;
 9564        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9565
 9566        let is_refreshing = provider.provider.is_refreshing(cx);
 9567
 9568        fn pending_completion_container(icon: IconName) -> Div {
 9569            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9570        }
 9571
 9572        let completion = match &self.active_edit_prediction {
 9573            Some(prediction) => {
 9574                if !self.has_visible_completions_menu() {
 9575                    const RADIUS: Pixels = px(6.);
 9576                    const BORDER_WIDTH: Pixels = px(1.);
 9577
 9578                    return Some(
 9579                        h_flex()
 9580                            .elevation_2(cx)
 9581                            .border(BORDER_WIDTH)
 9582                            .border_color(cx.theme().colors().border)
 9583                            .when(accept_keystroke.is_none(), |el| {
 9584                                el.border_color(cx.theme().status().error)
 9585                            })
 9586                            .rounded(RADIUS)
 9587                            .rounded_tl(px(0.))
 9588                            .overflow_hidden()
 9589                            .child(div().px_1p5().child(match &prediction.completion {
 9590                                EditPrediction::MoveWithin { target, snapshot } => {
 9591                                    use text::ToPoint as _;
 9592                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9593                                    {
 9594                                        Icon::new(IconName::ZedPredictDown)
 9595                                    } else {
 9596                                        Icon::new(IconName::ZedPredictUp)
 9597                                    }
 9598                                }
 9599                                EditPrediction::MoveOutside { .. } => {
 9600                                    // TODO [zeta2] custom icon for external jump?
 9601                                    Icon::new(provider_icon)
 9602                                }
 9603                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9604                            }))
 9605                            .child(
 9606                                h_flex()
 9607                                    .gap_1()
 9608                                    .py_1()
 9609                                    .px_2()
 9610                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9611                                    .border_l_1()
 9612                                    .border_color(cx.theme().colors().border)
 9613                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9614                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9615                                        el.child(
 9616                                            Label::new("Hold")
 9617                                                .size(LabelSize::Small)
 9618                                                .when(accept_keystroke.is_none(), |el| {
 9619                                                    el.strikethrough()
 9620                                                })
 9621                                                .line_height_style(LineHeightStyle::UiLabel),
 9622                                        )
 9623                                    })
 9624                                    .id("edit_prediction_cursor_popover_keybind")
 9625                                    .when(accept_keystroke.is_none(), |el| {
 9626                                        let status_colors = cx.theme().status();
 9627
 9628                                        el.bg(status_colors.error_background)
 9629                                            .border_color(status_colors.error.opacity(0.6))
 9630                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9631                                            .cursor_default()
 9632                                            .hoverable_tooltip(move |_window, cx| {
 9633                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9634                                                    .into()
 9635                                            })
 9636                                    })
 9637                                    .when_some(
 9638                                        accept_keystroke.as_ref(),
 9639                                        |el, accept_keystroke| {
 9640                                            el.child(h_flex().children(ui::render_modifiers(
 9641                                                accept_keystroke.modifiers(),
 9642                                                PlatformStyle::platform(),
 9643                                                Some(Color::Default),
 9644                                                Some(IconSize::XSmall.rems().into()),
 9645                                                false,
 9646                                            )))
 9647                                        },
 9648                                    ),
 9649                            )
 9650                            .into_any(),
 9651                    );
 9652                }
 9653
 9654                self.render_edit_prediction_cursor_popover_preview(
 9655                    prediction,
 9656                    cursor_point,
 9657                    style,
 9658                    cx,
 9659                )?
 9660            }
 9661
 9662            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9663                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9664                    stale_completion,
 9665                    cursor_point,
 9666                    style,
 9667                    cx,
 9668                )?,
 9669
 9670                None => pending_completion_container(provider_icon)
 9671                    .child(Label::new("...").size(LabelSize::Small)),
 9672            },
 9673
 9674            None => pending_completion_container(provider_icon)
 9675                .child(Label::new("...").size(LabelSize::Small)),
 9676        };
 9677
 9678        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9679            completion
 9680                .with_animation(
 9681                    "loading-completion",
 9682                    Animation::new(Duration::from_secs(2))
 9683                        .repeat()
 9684                        .with_easing(pulsating_between(0.4, 0.8)),
 9685                    |label, delta| label.opacity(delta),
 9686                )
 9687                .into_any_element()
 9688        } else {
 9689            completion.into_any_element()
 9690        };
 9691
 9692        let has_completion = self.active_edit_prediction.is_some();
 9693
 9694        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9695        Some(
 9696            h_flex()
 9697                .min_w(min_width)
 9698                .max_w(max_width)
 9699                .flex_1()
 9700                .elevation_2(cx)
 9701                .border_color(cx.theme().colors().border)
 9702                .child(
 9703                    div()
 9704                        .flex_1()
 9705                        .py_1()
 9706                        .px_2()
 9707                        .overflow_hidden()
 9708                        .child(completion),
 9709                )
 9710                .when_some(accept_keystroke, |el, accept_keystroke| {
 9711                    if !accept_keystroke.modifiers().modified() {
 9712                        return el;
 9713                    }
 9714
 9715                    el.child(
 9716                        h_flex()
 9717                            .h_full()
 9718                            .border_l_1()
 9719                            .rounded_r_lg()
 9720                            .border_color(cx.theme().colors().border)
 9721                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9722                            .gap_1()
 9723                            .py_1()
 9724                            .px_2()
 9725                            .child(
 9726                                h_flex()
 9727                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9728                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9729                                    .child(h_flex().children(ui::render_modifiers(
 9730                                        accept_keystroke.modifiers(),
 9731                                        PlatformStyle::platform(),
 9732                                        Some(if !has_completion {
 9733                                            Color::Muted
 9734                                        } else {
 9735                                            Color::Default
 9736                                        }),
 9737                                        None,
 9738                                        false,
 9739                                    ))),
 9740                            )
 9741                            .child(Label::new("Preview").into_any_element())
 9742                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9743                    )
 9744                })
 9745                .into_any(),
 9746        )
 9747    }
 9748
 9749    fn render_edit_prediction_cursor_popover_preview(
 9750        &self,
 9751        completion: &EditPredictionState,
 9752        cursor_point: Point,
 9753        style: &EditorStyle,
 9754        cx: &mut Context<Editor>,
 9755    ) -> Option<Div> {
 9756        use text::ToPoint as _;
 9757
 9758        fn render_relative_row_jump(
 9759            prefix: impl Into<String>,
 9760            current_row: u32,
 9761            target_row: u32,
 9762        ) -> Div {
 9763            let (row_diff, arrow) = if target_row < current_row {
 9764                (current_row - target_row, IconName::ArrowUp)
 9765            } else {
 9766                (target_row - current_row, IconName::ArrowDown)
 9767            };
 9768
 9769            h_flex()
 9770                .child(
 9771                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9772                        .color(Color::Muted)
 9773                        .size(LabelSize::Small),
 9774                )
 9775                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9776        }
 9777
 9778        let supports_jump = self
 9779            .edit_prediction_provider
 9780            .as_ref()
 9781            .map(|provider| provider.provider.supports_jump_to_edit())
 9782            .unwrap_or(true);
 9783
 9784        match &completion.completion {
 9785            EditPrediction::MoveWithin {
 9786                target, snapshot, ..
 9787            } => {
 9788                if !supports_jump {
 9789                    return None;
 9790                }
 9791
 9792                Some(
 9793                    h_flex()
 9794                        .px_2()
 9795                        .gap_2()
 9796                        .flex_1()
 9797                        .child(
 9798                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9799                                Icon::new(IconName::ZedPredictDown)
 9800                            } else {
 9801                                Icon::new(IconName::ZedPredictUp)
 9802                            },
 9803                        )
 9804                        .child(Label::new("Jump to Edit")),
 9805                )
 9806            }
 9807            EditPrediction::MoveOutside { snapshot, .. } => {
 9808                let file_name = snapshot
 9809                    .file()
 9810                    .map(|file| file.file_name(cx))
 9811                    .unwrap_or("untitled");
 9812                Some(
 9813                    h_flex()
 9814                        .px_2()
 9815                        .gap_2()
 9816                        .flex_1()
 9817                        .child(Icon::new(IconName::ZedPredict))
 9818                        .child(Label::new(format!("Jump to {file_name}"))),
 9819                )
 9820            }
 9821            EditPrediction::Edit {
 9822                edits,
 9823                edit_preview,
 9824                snapshot,
 9825                display_mode: _,
 9826            } => {
 9827                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9828
 9829                let (highlighted_edits, has_more_lines) =
 9830                    if let Some(edit_preview) = edit_preview.as_ref() {
 9831                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9832                            .first_line_preview()
 9833                    } else {
 9834                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9835                    };
 9836
 9837                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9838                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9839
 9840                let preview = h_flex()
 9841                    .gap_1()
 9842                    .min_w_16()
 9843                    .child(styled_text)
 9844                    .when(has_more_lines, |parent| parent.child(""));
 9845
 9846                let left = if supports_jump && first_edit_row != cursor_point.row {
 9847                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9848                        .into_any_element()
 9849                } else {
 9850                    let icon_name =
 9851                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9852                    Icon::new(icon_name).into_any_element()
 9853                };
 9854
 9855                Some(
 9856                    h_flex()
 9857                        .h_full()
 9858                        .flex_1()
 9859                        .gap_2()
 9860                        .pr_1()
 9861                        .overflow_x_hidden()
 9862                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9863                        .child(left)
 9864                        .child(preview),
 9865                )
 9866            }
 9867        }
 9868    }
 9869
 9870    pub fn render_context_menu(
 9871        &self,
 9872        style: &EditorStyle,
 9873        max_height_in_lines: u32,
 9874        window: &mut Window,
 9875        cx: &mut Context<Editor>,
 9876    ) -> Option<AnyElement> {
 9877        let menu = self.context_menu.borrow();
 9878        let menu = menu.as_ref()?;
 9879        if !menu.visible() {
 9880            return None;
 9881        };
 9882        Some(menu.render(style, max_height_in_lines, window, cx))
 9883    }
 9884
 9885    fn render_context_menu_aside(
 9886        &mut self,
 9887        max_size: Size<Pixels>,
 9888        window: &mut Window,
 9889        cx: &mut Context<Editor>,
 9890    ) -> Option<AnyElement> {
 9891        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9892            if menu.visible() {
 9893                menu.render_aside(max_size, window, cx)
 9894            } else {
 9895                None
 9896            }
 9897        })
 9898    }
 9899
 9900    fn hide_context_menu(
 9901        &mut self,
 9902        window: &mut Window,
 9903        cx: &mut Context<Self>,
 9904    ) -> Option<CodeContextMenu> {
 9905        cx.notify();
 9906        self.completion_tasks.clear();
 9907        let context_menu = self.context_menu.borrow_mut().take();
 9908        self.stale_edit_prediction_in_menu.take();
 9909        self.update_visible_edit_prediction(window, cx);
 9910        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9911            && let Some(completion_provider) = &self.completion_provider
 9912        {
 9913            completion_provider.selection_changed(None, window, cx);
 9914        }
 9915        context_menu
 9916    }
 9917
 9918    fn show_snippet_choices(
 9919        &mut self,
 9920        choices: &Vec<String>,
 9921        selection: Range<Anchor>,
 9922        cx: &mut Context<Self>,
 9923    ) {
 9924        let Some((_, buffer, _)) = self
 9925            .buffer()
 9926            .read(cx)
 9927            .excerpt_containing(selection.start, cx)
 9928        else {
 9929            return;
 9930        };
 9931        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9932        else {
 9933            return;
 9934        };
 9935        if buffer != end_buffer {
 9936            log::error!("expected anchor range to have matching buffer IDs");
 9937            return;
 9938        }
 9939
 9940        let id = post_inc(&mut self.next_completion_id);
 9941        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9942        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9943            CompletionsMenu::new_snippet_choices(
 9944                id,
 9945                true,
 9946                choices,
 9947                selection,
 9948                buffer,
 9949                snippet_sort_order,
 9950            ),
 9951        ));
 9952    }
 9953
 9954    pub fn insert_snippet(
 9955        &mut self,
 9956        insertion_ranges: &[Range<MultiBufferOffset>],
 9957        snippet: Snippet,
 9958        window: &mut Window,
 9959        cx: &mut Context<Self>,
 9960    ) -> Result<()> {
 9961        struct Tabstop<T> {
 9962            is_end_tabstop: bool,
 9963            ranges: Vec<Range<T>>,
 9964            choices: Option<Vec<String>>,
 9965        }
 9966
 9967        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9968            let snippet_text: Arc<str> = snippet.text.clone().into();
 9969            let edits = insertion_ranges
 9970                .iter()
 9971                .cloned()
 9972                .map(|range| (range, snippet_text.clone()));
 9973            let autoindent_mode = AutoindentMode::Block {
 9974                original_indent_columns: Vec::new(),
 9975            };
 9976            buffer.edit(edits, Some(autoindent_mode), cx);
 9977
 9978            let snapshot = &*buffer.read(cx);
 9979            let snippet = &snippet;
 9980            snippet
 9981                .tabstops
 9982                .iter()
 9983                .map(|tabstop| {
 9984                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9985                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9986                    });
 9987                    let mut tabstop_ranges = tabstop
 9988                        .ranges
 9989                        .iter()
 9990                        .flat_map(|tabstop_range| {
 9991                            let mut delta = 0_isize;
 9992                            insertion_ranges.iter().map(move |insertion_range| {
 9993                                let insertion_start = insertion_range.start + delta;
 9994                                delta += snippet.text.len() as isize
 9995                                    - (insertion_range.end - insertion_range.start) as isize;
 9996
 9997                                let start =
 9998                                    (insertion_start + tabstop_range.start).min(snapshot.len());
 9999                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10000                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10001                            })
10002                        })
10003                        .collect::<Vec<_>>();
10004                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10005
10006                    Tabstop {
10007                        is_end_tabstop,
10008                        ranges: tabstop_ranges,
10009                        choices: tabstop.choices.clone(),
10010                    }
10011                })
10012                .collect::<Vec<_>>()
10013        });
10014        if let Some(tabstop) = tabstops.first() {
10015            self.change_selections(Default::default(), window, cx, |s| {
10016                // Reverse order so that the first range is the newest created selection.
10017                // Completions will use it and autoscroll will prioritize it.
10018                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10019            });
10020
10021            if let Some(choices) = &tabstop.choices
10022                && let Some(selection) = tabstop.ranges.first()
10023            {
10024                self.show_snippet_choices(choices, selection.clone(), cx)
10025            }
10026
10027            // If we're already at the last tabstop and it's at the end of the snippet,
10028            // we're done, we don't need to keep the state around.
10029            if !tabstop.is_end_tabstop {
10030                let choices = tabstops
10031                    .iter()
10032                    .map(|tabstop| tabstop.choices.clone())
10033                    .collect();
10034
10035                let ranges = tabstops
10036                    .into_iter()
10037                    .map(|tabstop| tabstop.ranges)
10038                    .collect::<Vec<_>>();
10039
10040                self.snippet_stack.push(SnippetState {
10041                    active_index: 0,
10042                    ranges,
10043                    choices,
10044                });
10045            }
10046
10047            // Check whether the just-entered snippet ends with an auto-closable bracket.
10048            if self.autoclose_regions.is_empty() {
10049                let snapshot = self.buffer.read(cx).snapshot(cx);
10050                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10051                    let selection_head = selection.head();
10052                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10053                        continue;
10054                    };
10055
10056                    let mut bracket_pair = None;
10057                    let max_lookup_length = scope
10058                        .brackets()
10059                        .map(|(pair, _)| {
10060                            pair.start
10061                                .as_str()
10062                                .chars()
10063                                .count()
10064                                .max(pair.end.as_str().chars().count())
10065                        })
10066                        .max();
10067                    if let Some(max_lookup_length) = max_lookup_length {
10068                        let next_text = snapshot
10069                            .chars_at(selection_head)
10070                            .take(max_lookup_length)
10071                            .collect::<String>();
10072                        let prev_text = snapshot
10073                            .reversed_chars_at(selection_head)
10074                            .take(max_lookup_length)
10075                            .collect::<String>();
10076
10077                        for (pair, enabled) in scope.brackets() {
10078                            if enabled
10079                                && pair.close
10080                                && prev_text.starts_with(pair.start.as_str())
10081                                && next_text.starts_with(pair.end.as_str())
10082                            {
10083                                bracket_pair = Some(pair.clone());
10084                                break;
10085                            }
10086                        }
10087                    }
10088
10089                    if let Some(pair) = bracket_pair {
10090                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10091                        let autoclose_enabled =
10092                            self.use_autoclose && snapshot_settings.use_autoclose;
10093                        if autoclose_enabled {
10094                            let start = snapshot.anchor_after(selection_head);
10095                            let end = snapshot.anchor_after(selection_head);
10096                            self.autoclose_regions.push(AutocloseRegion {
10097                                selection_id: selection.id,
10098                                range: start..end,
10099                                pair,
10100                            });
10101                        }
10102                    }
10103                }
10104            }
10105        }
10106        Ok(())
10107    }
10108
10109    pub fn move_to_next_snippet_tabstop(
10110        &mut self,
10111        window: &mut Window,
10112        cx: &mut Context<Self>,
10113    ) -> bool {
10114        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10115    }
10116
10117    pub fn move_to_prev_snippet_tabstop(
10118        &mut self,
10119        window: &mut Window,
10120        cx: &mut Context<Self>,
10121    ) -> bool {
10122        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10123    }
10124
10125    pub fn move_to_snippet_tabstop(
10126        &mut self,
10127        bias: Bias,
10128        window: &mut Window,
10129        cx: &mut Context<Self>,
10130    ) -> bool {
10131        if let Some(mut snippet) = self.snippet_stack.pop() {
10132            match bias {
10133                Bias::Left => {
10134                    if snippet.active_index > 0 {
10135                        snippet.active_index -= 1;
10136                    } else {
10137                        self.snippet_stack.push(snippet);
10138                        return false;
10139                    }
10140                }
10141                Bias::Right => {
10142                    if snippet.active_index + 1 < snippet.ranges.len() {
10143                        snippet.active_index += 1;
10144                    } else {
10145                        self.snippet_stack.push(snippet);
10146                        return false;
10147                    }
10148                }
10149            }
10150            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10151                self.change_selections(Default::default(), window, cx, |s| {
10152                    // Reverse order so that the first range is the newest created selection.
10153                    // Completions will use it and autoscroll will prioritize it.
10154                    s.select_ranges(current_ranges.iter().rev().cloned())
10155                });
10156
10157                if let Some(choices) = &snippet.choices[snippet.active_index]
10158                    && let Some(selection) = current_ranges.first()
10159                {
10160                    self.show_snippet_choices(choices, selection.clone(), cx);
10161                }
10162
10163                // If snippet state is not at the last tabstop, push it back on the stack
10164                if snippet.active_index + 1 < snippet.ranges.len() {
10165                    self.snippet_stack.push(snippet);
10166                }
10167                return true;
10168            }
10169        }
10170
10171        false
10172    }
10173
10174    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10175        self.transact(window, cx, |this, window, cx| {
10176            this.select_all(&SelectAll, window, cx);
10177            this.insert("", window, cx);
10178        });
10179    }
10180
10181    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10182        if self.read_only(cx) {
10183            return;
10184        }
10185        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10186        self.transact(window, cx, |this, window, cx| {
10187            this.select_autoclose_pair(window, cx);
10188
10189            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10190
10191            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10192            if !this.linked_edit_ranges.is_empty() {
10193                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10194                let snapshot = this.buffer.read(cx).snapshot(cx);
10195
10196                for selection in selections.iter() {
10197                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10198                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10199                    if selection_start.buffer_id != selection_end.buffer_id {
10200                        continue;
10201                    }
10202                    if let Some(ranges) =
10203                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10204                    {
10205                        for (buffer, entries) in ranges {
10206                            linked_ranges.entry(buffer).or_default().extend(entries);
10207                        }
10208                    }
10209                }
10210            }
10211
10212            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10213            for selection in &mut selections {
10214                if selection.is_empty() {
10215                    let old_head = selection.head();
10216                    let mut new_head =
10217                        movement::left(&display_map, old_head.to_display_point(&display_map))
10218                            .to_point(&display_map);
10219                    if let Some((buffer, line_buffer_range)) = display_map
10220                        .buffer_snapshot()
10221                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10222                    {
10223                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10224                        let indent_len = match indent_size.kind {
10225                            IndentKind::Space => {
10226                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10227                            }
10228                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10229                        };
10230                        if old_head.column <= indent_size.len && old_head.column > 0 {
10231                            let indent_len = indent_len.get();
10232                            new_head = cmp::min(
10233                                new_head,
10234                                MultiBufferPoint::new(
10235                                    old_head.row,
10236                                    ((old_head.column - 1) / indent_len) * indent_len,
10237                                ),
10238                            );
10239                        }
10240                    }
10241
10242                    selection.set_head(new_head, SelectionGoal::None);
10243                }
10244            }
10245
10246            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10247            this.insert("", window, cx);
10248            let empty_str: Arc<str> = Arc::from("");
10249            for (buffer, edits) in linked_ranges {
10250                let snapshot = buffer.read(cx).snapshot();
10251                use text::ToPoint as TP;
10252
10253                let edits = edits
10254                    .into_iter()
10255                    .map(|range| {
10256                        let end_point = TP::to_point(&range.end, &snapshot);
10257                        let mut start_point = TP::to_point(&range.start, &snapshot);
10258
10259                        if end_point == start_point {
10260                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10261                                .saturating_sub(1);
10262                            start_point =
10263                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10264                        };
10265
10266                        (start_point..end_point, empty_str.clone())
10267                    })
10268                    .sorted_by_key(|(range, _)| range.start)
10269                    .collect::<Vec<_>>();
10270                buffer.update(cx, |this, cx| {
10271                    this.edit(edits, None, cx);
10272                })
10273            }
10274            this.refresh_edit_prediction(true, false, window, cx);
10275            refresh_linked_ranges(this, window, cx);
10276        });
10277    }
10278
10279    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10280        if self.read_only(cx) {
10281            return;
10282        }
10283        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10284        self.transact(window, cx, |this, window, cx| {
10285            this.change_selections(Default::default(), window, cx, |s| {
10286                s.move_with(|map, selection| {
10287                    if selection.is_empty() {
10288                        let cursor = movement::right(map, selection.head());
10289                        selection.end = cursor;
10290                        selection.reversed = true;
10291                        selection.goal = SelectionGoal::None;
10292                    }
10293                })
10294            });
10295            this.insert("", window, cx);
10296            this.refresh_edit_prediction(true, false, window, cx);
10297        });
10298    }
10299
10300    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10301        if self.mode.is_single_line() {
10302            cx.propagate();
10303            return;
10304        }
10305
10306        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10307        if self.move_to_prev_snippet_tabstop(window, cx) {
10308            return;
10309        }
10310        self.outdent(&Outdent, window, cx);
10311    }
10312
10313    pub fn next_snippet_tabstop(
10314        &mut self,
10315        _: &NextSnippetTabstop,
10316        window: &mut Window,
10317        cx: &mut Context<Self>,
10318    ) {
10319        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10320            cx.propagate();
10321            return;
10322        }
10323
10324        if self.move_to_next_snippet_tabstop(window, cx) {
10325            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10326            return;
10327        }
10328        cx.propagate();
10329    }
10330
10331    pub fn previous_snippet_tabstop(
10332        &mut self,
10333        _: &PreviousSnippetTabstop,
10334        window: &mut Window,
10335        cx: &mut Context<Self>,
10336    ) {
10337        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10338            cx.propagate();
10339            return;
10340        }
10341
10342        if self.move_to_prev_snippet_tabstop(window, cx) {
10343            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10344            return;
10345        }
10346        cx.propagate();
10347    }
10348
10349    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10350        if self.mode.is_single_line() {
10351            cx.propagate();
10352            return;
10353        }
10354
10355        if self.move_to_next_snippet_tabstop(window, cx) {
10356            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10357            return;
10358        }
10359        if self.read_only(cx) {
10360            return;
10361        }
10362        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10363        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10364        let buffer = self.buffer.read(cx);
10365        let snapshot = buffer.snapshot(cx);
10366        let rows_iter = selections.iter().map(|s| s.head().row);
10367        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10368
10369        let has_some_cursor_in_whitespace = selections
10370            .iter()
10371            .filter(|selection| selection.is_empty())
10372            .any(|selection| {
10373                let cursor = selection.head();
10374                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10375                cursor.column < current_indent.len
10376            });
10377
10378        let mut edits = Vec::new();
10379        let mut prev_edited_row = 0;
10380        let mut row_delta = 0;
10381        for selection in &mut selections {
10382            if selection.start.row != prev_edited_row {
10383                row_delta = 0;
10384            }
10385            prev_edited_row = selection.end.row;
10386
10387            // If the selection is non-empty, then increase the indentation of the selected lines.
10388            if !selection.is_empty() {
10389                row_delta =
10390                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10391                continue;
10392            }
10393
10394            let cursor = selection.head();
10395            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10396            if let Some(suggested_indent) =
10397                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10398            {
10399                // Don't do anything if already at suggested indent
10400                // and there is any other cursor which is not
10401                if has_some_cursor_in_whitespace
10402                    && cursor.column == current_indent.len
10403                    && current_indent.len == suggested_indent.len
10404                {
10405                    continue;
10406                }
10407
10408                // Adjust line and move cursor to suggested indent
10409                // if cursor is not at suggested indent
10410                if cursor.column < suggested_indent.len
10411                    && cursor.column <= current_indent.len
10412                    && current_indent.len <= suggested_indent.len
10413                {
10414                    selection.start = Point::new(cursor.row, suggested_indent.len);
10415                    selection.end = selection.start;
10416                    if row_delta == 0 {
10417                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10418                            cursor.row,
10419                            current_indent,
10420                            suggested_indent,
10421                        ));
10422                        row_delta = suggested_indent.len - current_indent.len;
10423                    }
10424                    continue;
10425                }
10426
10427                // If current indent is more than suggested indent
10428                // only move cursor to current indent and skip indent
10429                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10430                    selection.start = Point::new(cursor.row, current_indent.len);
10431                    selection.end = selection.start;
10432                    continue;
10433                }
10434            }
10435
10436            // Otherwise, insert a hard or soft tab.
10437            let settings = buffer.language_settings_at(cursor, cx);
10438            let tab_size = if settings.hard_tabs {
10439                IndentSize::tab()
10440            } else {
10441                let tab_size = settings.tab_size.get();
10442                let indent_remainder = snapshot
10443                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10444                    .flat_map(str::chars)
10445                    .fold(row_delta % tab_size, |counter: u32, c| {
10446                        if c == '\t' {
10447                            0
10448                        } else {
10449                            (counter + 1) % tab_size
10450                        }
10451                    });
10452
10453                let chars_to_next_tab_stop = tab_size - indent_remainder;
10454                IndentSize::spaces(chars_to_next_tab_stop)
10455            };
10456            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10457            selection.end = selection.start;
10458            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10459            row_delta += tab_size.len;
10460        }
10461
10462        self.transact(window, cx, |this, window, cx| {
10463            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10464            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10465            this.refresh_edit_prediction(true, false, window, cx);
10466        });
10467    }
10468
10469    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10470        if self.read_only(cx) {
10471            return;
10472        }
10473        if self.mode.is_single_line() {
10474            cx.propagate();
10475            return;
10476        }
10477
10478        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10479        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10480        let mut prev_edited_row = 0;
10481        let mut row_delta = 0;
10482        let mut edits = Vec::new();
10483        let buffer = self.buffer.read(cx);
10484        let snapshot = buffer.snapshot(cx);
10485        for selection in &mut selections {
10486            if selection.start.row != prev_edited_row {
10487                row_delta = 0;
10488            }
10489            prev_edited_row = selection.end.row;
10490
10491            row_delta =
10492                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10493        }
10494
10495        self.transact(window, cx, |this, window, cx| {
10496            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10497            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10498        });
10499    }
10500
10501    fn indent_selection(
10502        buffer: &MultiBuffer,
10503        snapshot: &MultiBufferSnapshot,
10504        selection: &mut Selection<Point>,
10505        edits: &mut Vec<(Range<Point>, String)>,
10506        delta_for_start_row: u32,
10507        cx: &App,
10508    ) -> u32 {
10509        let settings = buffer.language_settings_at(selection.start, cx);
10510        let tab_size = settings.tab_size.get();
10511        let indent_kind = if settings.hard_tabs {
10512            IndentKind::Tab
10513        } else {
10514            IndentKind::Space
10515        };
10516        let mut start_row = selection.start.row;
10517        let mut end_row = selection.end.row + 1;
10518
10519        // If a selection ends at the beginning of a line, don't indent
10520        // that last line.
10521        if selection.end.column == 0 && selection.end.row > selection.start.row {
10522            end_row -= 1;
10523        }
10524
10525        // Avoid re-indenting a row that has already been indented by a
10526        // previous selection, but still update this selection's column
10527        // to reflect that indentation.
10528        if delta_for_start_row > 0 {
10529            start_row += 1;
10530            selection.start.column += delta_for_start_row;
10531            if selection.end.row == selection.start.row {
10532                selection.end.column += delta_for_start_row;
10533            }
10534        }
10535
10536        let mut delta_for_end_row = 0;
10537        let has_multiple_rows = start_row + 1 != end_row;
10538        for row in start_row..end_row {
10539            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10540            let indent_delta = match (current_indent.kind, indent_kind) {
10541                (IndentKind::Space, IndentKind::Space) => {
10542                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10543                    IndentSize::spaces(columns_to_next_tab_stop)
10544                }
10545                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10546                (_, IndentKind::Tab) => IndentSize::tab(),
10547            };
10548
10549            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10550                0
10551            } else {
10552                selection.start.column
10553            };
10554            let row_start = Point::new(row, start);
10555            edits.push((
10556                row_start..row_start,
10557                indent_delta.chars().collect::<String>(),
10558            ));
10559
10560            // Update this selection's endpoints to reflect the indentation.
10561            if row == selection.start.row {
10562                selection.start.column += indent_delta.len;
10563            }
10564            if row == selection.end.row {
10565                selection.end.column += indent_delta.len;
10566                delta_for_end_row = indent_delta.len;
10567            }
10568        }
10569
10570        if selection.start.row == selection.end.row {
10571            delta_for_start_row + delta_for_end_row
10572        } else {
10573            delta_for_end_row
10574        }
10575    }
10576
10577    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10578        if self.read_only(cx) {
10579            return;
10580        }
10581        if self.mode.is_single_line() {
10582            cx.propagate();
10583            return;
10584        }
10585
10586        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10587        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10588        let selections = self.selections.all::<Point>(&display_map);
10589        let mut deletion_ranges = Vec::new();
10590        let mut last_outdent = None;
10591        {
10592            let buffer = self.buffer.read(cx);
10593            let snapshot = buffer.snapshot(cx);
10594            for selection in &selections {
10595                let settings = buffer.language_settings_at(selection.start, cx);
10596                let tab_size = settings.tab_size.get();
10597                let mut rows = selection.spanned_rows(false, &display_map);
10598
10599                // Avoid re-outdenting a row that has already been outdented by a
10600                // previous selection.
10601                if let Some(last_row) = last_outdent
10602                    && last_row == rows.start
10603                {
10604                    rows.start = rows.start.next_row();
10605                }
10606                let has_multiple_rows = rows.len() > 1;
10607                for row in rows.iter_rows() {
10608                    let indent_size = snapshot.indent_size_for_line(row);
10609                    if indent_size.len > 0 {
10610                        let deletion_len = match indent_size.kind {
10611                            IndentKind::Space => {
10612                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10613                                if columns_to_prev_tab_stop == 0 {
10614                                    tab_size
10615                                } else {
10616                                    columns_to_prev_tab_stop
10617                                }
10618                            }
10619                            IndentKind::Tab => 1,
10620                        };
10621                        let start = if has_multiple_rows
10622                            || deletion_len > selection.start.column
10623                            || indent_size.len < selection.start.column
10624                        {
10625                            0
10626                        } else {
10627                            selection.start.column - deletion_len
10628                        };
10629                        deletion_ranges.push(
10630                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10631                        );
10632                        last_outdent = Some(row);
10633                    }
10634                }
10635            }
10636        }
10637
10638        self.transact(window, cx, |this, window, cx| {
10639            this.buffer.update(cx, |buffer, cx| {
10640                let empty_str: Arc<str> = Arc::default();
10641                buffer.edit(
10642                    deletion_ranges
10643                        .into_iter()
10644                        .map(|range| (range, empty_str.clone())),
10645                    None,
10646                    cx,
10647                );
10648            });
10649            let selections = this
10650                .selections
10651                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10652            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10653        });
10654    }
10655
10656    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10657        if self.read_only(cx) {
10658            return;
10659        }
10660        if self.mode.is_single_line() {
10661            cx.propagate();
10662            return;
10663        }
10664
10665        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10666        let selections = self
10667            .selections
10668            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10669            .into_iter()
10670            .map(|s| s.range());
10671
10672        self.transact(window, cx, |this, window, cx| {
10673            this.buffer.update(cx, |buffer, cx| {
10674                buffer.autoindent_ranges(selections, cx);
10675            });
10676            let selections = this
10677                .selections
10678                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10679            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10680        });
10681    }
10682
10683    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10684        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10685        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10686        let selections = self.selections.all::<Point>(&display_map);
10687
10688        let mut new_cursors = Vec::new();
10689        let mut edit_ranges = Vec::new();
10690        let mut selections = selections.iter().peekable();
10691        while let Some(selection) = selections.next() {
10692            let mut rows = selection.spanned_rows(false, &display_map);
10693
10694            // Accumulate contiguous regions of rows that we want to delete.
10695            while let Some(next_selection) = selections.peek() {
10696                let next_rows = next_selection.spanned_rows(false, &display_map);
10697                if next_rows.start <= rows.end {
10698                    rows.end = next_rows.end;
10699                    selections.next().unwrap();
10700                } else {
10701                    break;
10702                }
10703            }
10704
10705            let buffer = display_map.buffer_snapshot();
10706            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10707            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10708                // If there's a line after the range, delete the \n from the end of the row range
10709                (
10710                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10711                    rows.end,
10712                )
10713            } else {
10714                // If there isn't a line after the range, delete the \n from the line before the
10715                // start of the row range
10716                edit_start = edit_start.saturating_sub_usize(1);
10717                (buffer.len(), rows.start.previous_row())
10718            };
10719
10720            let text_layout_details = self.text_layout_details(window);
10721            let x = display_map.x_for_display_point(
10722                selection.head().to_display_point(&display_map),
10723                &text_layout_details,
10724            );
10725            let row = Point::new(target_row.0, 0)
10726                .to_display_point(&display_map)
10727                .row();
10728            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10729
10730            new_cursors.push((
10731                selection.id,
10732                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10733                SelectionGoal::None,
10734            ));
10735            edit_ranges.push(edit_start..edit_end);
10736        }
10737
10738        self.transact(window, cx, |this, window, cx| {
10739            let buffer = this.buffer.update(cx, |buffer, cx| {
10740                let empty_str: Arc<str> = Arc::default();
10741                buffer.edit(
10742                    edit_ranges
10743                        .into_iter()
10744                        .map(|range| (range, empty_str.clone())),
10745                    None,
10746                    cx,
10747                );
10748                buffer.snapshot(cx)
10749            });
10750            let new_selections = new_cursors
10751                .into_iter()
10752                .map(|(id, cursor, goal)| {
10753                    let cursor = cursor.to_point(&buffer);
10754                    Selection {
10755                        id,
10756                        start: cursor,
10757                        end: cursor,
10758                        reversed: false,
10759                        goal,
10760                    }
10761                })
10762                .collect();
10763
10764            this.change_selections(Default::default(), window, cx, |s| {
10765                s.select(new_selections);
10766            });
10767        });
10768    }
10769
10770    pub fn join_lines_impl(
10771        &mut self,
10772        insert_whitespace: bool,
10773        window: &mut Window,
10774        cx: &mut Context<Self>,
10775    ) {
10776        if self.read_only(cx) {
10777            return;
10778        }
10779        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10780        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10781            let start = MultiBufferRow(selection.start.row);
10782            // Treat single line selections as if they include the next line. Otherwise this action
10783            // would do nothing for single line selections individual cursors.
10784            let end = if selection.start.row == selection.end.row {
10785                MultiBufferRow(selection.start.row + 1)
10786            } else {
10787                MultiBufferRow(selection.end.row)
10788            };
10789
10790            if let Some(last_row_range) = row_ranges.last_mut()
10791                && start <= last_row_range.end
10792            {
10793                last_row_range.end = end;
10794                continue;
10795            }
10796            row_ranges.push(start..end);
10797        }
10798
10799        let snapshot = self.buffer.read(cx).snapshot(cx);
10800        let mut cursor_positions = Vec::new();
10801        for row_range in &row_ranges {
10802            let anchor = snapshot.anchor_before(Point::new(
10803                row_range.end.previous_row().0,
10804                snapshot.line_len(row_range.end.previous_row()),
10805            ));
10806            cursor_positions.push(anchor..anchor);
10807        }
10808
10809        self.transact(window, cx, |this, window, cx| {
10810            for row_range in row_ranges.into_iter().rev() {
10811                for row in row_range.iter_rows().rev() {
10812                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10813                    let next_line_row = row.next_row();
10814                    let indent = snapshot.indent_size_for_line(next_line_row);
10815                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10816
10817                    let replace =
10818                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10819                            " "
10820                        } else {
10821                            ""
10822                        };
10823
10824                    this.buffer.update(cx, |buffer, cx| {
10825                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10826                    });
10827                }
10828            }
10829
10830            this.change_selections(Default::default(), window, cx, |s| {
10831                s.select_anchor_ranges(cursor_positions)
10832            });
10833        });
10834    }
10835
10836    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10837        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10838        self.join_lines_impl(true, window, cx);
10839    }
10840
10841    pub fn sort_lines_case_sensitive(
10842        &mut self,
10843        _: &SortLinesCaseSensitive,
10844        window: &mut Window,
10845        cx: &mut Context<Self>,
10846    ) {
10847        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10848    }
10849
10850    pub fn sort_lines_by_length(
10851        &mut self,
10852        _: &SortLinesByLength,
10853        window: &mut Window,
10854        cx: &mut Context<Self>,
10855    ) {
10856        self.manipulate_immutable_lines(window, cx, |lines| {
10857            lines.sort_by_key(|&line| line.chars().count())
10858        })
10859    }
10860
10861    pub fn sort_lines_case_insensitive(
10862        &mut self,
10863        _: &SortLinesCaseInsensitive,
10864        window: &mut Window,
10865        cx: &mut Context<Self>,
10866    ) {
10867        self.manipulate_immutable_lines(window, cx, |lines| {
10868            lines.sort_by_key(|line| line.to_lowercase())
10869        })
10870    }
10871
10872    pub fn unique_lines_case_insensitive(
10873        &mut self,
10874        _: &UniqueLinesCaseInsensitive,
10875        window: &mut Window,
10876        cx: &mut Context<Self>,
10877    ) {
10878        self.manipulate_immutable_lines(window, cx, |lines| {
10879            let mut seen = HashSet::default();
10880            lines.retain(|line| seen.insert(line.to_lowercase()));
10881        })
10882    }
10883
10884    pub fn unique_lines_case_sensitive(
10885        &mut self,
10886        _: &UniqueLinesCaseSensitive,
10887        window: &mut Window,
10888        cx: &mut Context<Self>,
10889    ) {
10890        self.manipulate_immutable_lines(window, cx, |lines| {
10891            let mut seen = HashSet::default();
10892            lines.retain(|line| seen.insert(*line));
10893        })
10894    }
10895
10896    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10897        let snapshot = self.buffer.read(cx).snapshot(cx);
10898        for selection in self.selections.disjoint_anchors_arc().iter() {
10899            if snapshot
10900                .language_at(selection.start)
10901                .and_then(|lang| lang.config().wrap_characters.as_ref())
10902                .is_some()
10903            {
10904                return true;
10905            }
10906        }
10907        false
10908    }
10909
10910    fn wrap_selections_in_tag(
10911        &mut self,
10912        _: &WrapSelectionsInTag,
10913        window: &mut Window,
10914        cx: &mut Context<Self>,
10915    ) {
10916        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10917
10918        let snapshot = self.buffer.read(cx).snapshot(cx);
10919
10920        let mut edits = Vec::new();
10921        let mut boundaries = Vec::new();
10922
10923        for selection in self
10924            .selections
10925            .all_adjusted(&self.display_snapshot(cx))
10926            .iter()
10927        {
10928            let Some(wrap_config) = snapshot
10929                .language_at(selection.start)
10930                .and_then(|lang| lang.config().wrap_characters.clone())
10931            else {
10932                continue;
10933            };
10934
10935            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10936            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10937
10938            let start_before = snapshot.anchor_before(selection.start);
10939            let end_after = snapshot.anchor_after(selection.end);
10940
10941            edits.push((start_before..start_before, open_tag));
10942            edits.push((end_after..end_after, close_tag));
10943
10944            boundaries.push((
10945                start_before,
10946                end_after,
10947                wrap_config.start_prefix.len(),
10948                wrap_config.end_suffix.len(),
10949            ));
10950        }
10951
10952        if edits.is_empty() {
10953            return;
10954        }
10955
10956        self.transact(window, cx, |this, window, cx| {
10957            let buffer = this.buffer.update(cx, |buffer, cx| {
10958                buffer.edit(edits, None, cx);
10959                buffer.snapshot(cx)
10960            });
10961
10962            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10963            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10964                boundaries.into_iter()
10965            {
10966                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10967                let close_offset = end_after
10968                    .to_offset(&buffer)
10969                    .saturating_sub_usize(end_suffix_len);
10970                new_selections.push(open_offset..open_offset);
10971                new_selections.push(close_offset..close_offset);
10972            }
10973
10974            this.change_selections(Default::default(), window, cx, |s| {
10975                s.select_ranges(new_selections);
10976            });
10977
10978            this.request_autoscroll(Autoscroll::fit(), cx);
10979        });
10980    }
10981
10982    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10983        let Some(project) = self.project.clone() else {
10984            return;
10985        };
10986        self.reload(project, window, cx)
10987            .detach_and_notify_err(window, cx);
10988    }
10989
10990    pub fn restore_file(
10991        &mut self,
10992        _: &::git::RestoreFile,
10993        window: &mut Window,
10994        cx: &mut Context<Self>,
10995    ) {
10996        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10997        let mut buffer_ids = HashSet::default();
10998        let snapshot = self.buffer().read(cx).snapshot(cx);
10999        for selection in self
11000            .selections
11001            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11002        {
11003            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11004        }
11005
11006        let buffer = self.buffer().read(cx);
11007        let ranges = buffer_ids
11008            .into_iter()
11009            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11010            .collect::<Vec<_>>();
11011
11012        self.restore_hunks_in_ranges(ranges, window, cx);
11013    }
11014
11015    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11016        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11017        let selections = self
11018            .selections
11019            .all(&self.display_snapshot(cx))
11020            .into_iter()
11021            .map(|s| s.range())
11022            .collect();
11023        self.restore_hunks_in_ranges(selections, window, cx);
11024    }
11025
11026    pub fn restore_hunks_in_ranges(
11027        &mut self,
11028        ranges: Vec<Range<Point>>,
11029        window: &mut Window,
11030        cx: &mut Context<Editor>,
11031    ) {
11032        let mut revert_changes = HashMap::default();
11033        let chunk_by = self
11034            .snapshot(window, cx)
11035            .hunks_for_ranges(ranges)
11036            .into_iter()
11037            .chunk_by(|hunk| hunk.buffer_id);
11038        for (buffer_id, hunks) in &chunk_by {
11039            let hunks = hunks.collect::<Vec<_>>();
11040            for hunk in &hunks {
11041                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11042            }
11043            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11044        }
11045        drop(chunk_by);
11046        if !revert_changes.is_empty() {
11047            self.transact(window, cx, |editor, window, cx| {
11048                editor.restore(revert_changes, window, cx);
11049            });
11050        }
11051    }
11052
11053    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11054        if let Some(status) = self
11055            .addons
11056            .iter()
11057            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11058        {
11059            return Some(status);
11060        }
11061        self.project
11062            .as_ref()?
11063            .read(cx)
11064            .status_for_buffer_id(buffer_id, cx)
11065    }
11066
11067    pub fn open_active_item_in_terminal(
11068        &mut self,
11069        _: &OpenInTerminal,
11070        window: &mut Window,
11071        cx: &mut Context<Self>,
11072    ) {
11073        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11074            let project_path = buffer.read(cx).project_path(cx)?;
11075            let project = self.project()?.read(cx);
11076            let entry = project.entry_for_path(&project_path, cx)?;
11077            let parent = match &entry.canonical_path {
11078                Some(canonical_path) => canonical_path.to_path_buf(),
11079                None => project.absolute_path(&project_path, cx)?,
11080            }
11081            .parent()?
11082            .to_path_buf();
11083            Some(parent)
11084        }) {
11085            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11086        }
11087    }
11088
11089    fn set_breakpoint_context_menu(
11090        &mut self,
11091        display_row: DisplayRow,
11092        position: Option<Anchor>,
11093        clicked_point: gpui::Point<Pixels>,
11094        window: &mut Window,
11095        cx: &mut Context<Self>,
11096    ) {
11097        let source = self
11098            .buffer
11099            .read(cx)
11100            .snapshot(cx)
11101            .anchor_before(Point::new(display_row.0, 0u32));
11102
11103        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11104
11105        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11106            self,
11107            source,
11108            clicked_point,
11109            context_menu,
11110            window,
11111            cx,
11112        );
11113    }
11114
11115    fn add_edit_breakpoint_block(
11116        &mut self,
11117        anchor: Anchor,
11118        breakpoint: &Breakpoint,
11119        edit_action: BreakpointPromptEditAction,
11120        window: &mut Window,
11121        cx: &mut Context<Self>,
11122    ) {
11123        let weak_editor = cx.weak_entity();
11124        let bp_prompt = cx.new(|cx| {
11125            BreakpointPromptEditor::new(
11126                weak_editor,
11127                anchor,
11128                breakpoint.clone(),
11129                edit_action,
11130                window,
11131                cx,
11132            )
11133        });
11134
11135        let height = bp_prompt.update(cx, |this, cx| {
11136            this.prompt
11137                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11138        });
11139        let cloned_prompt = bp_prompt.clone();
11140        let blocks = vec![BlockProperties {
11141            style: BlockStyle::Sticky,
11142            placement: BlockPlacement::Above(anchor),
11143            height: Some(height),
11144            render: Arc::new(move |cx| {
11145                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11146                cloned_prompt.clone().into_any_element()
11147            }),
11148            priority: 0,
11149        }];
11150
11151        let focus_handle = bp_prompt.focus_handle(cx);
11152        window.focus(&focus_handle);
11153
11154        let block_ids = self.insert_blocks(blocks, None, cx);
11155        bp_prompt.update(cx, |prompt, _| {
11156            prompt.add_block_ids(block_ids);
11157        });
11158    }
11159
11160    pub(crate) fn breakpoint_at_row(
11161        &self,
11162        row: u32,
11163        window: &mut Window,
11164        cx: &mut Context<Self>,
11165    ) -> Option<(Anchor, Breakpoint)> {
11166        let snapshot = self.snapshot(window, cx);
11167        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11168
11169        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11170    }
11171
11172    pub(crate) fn breakpoint_at_anchor(
11173        &self,
11174        breakpoint_position: Anchor,
11175        snapshot: &EditorSnapshot,
11176        cx: &mut Context<Self>,
11177    ) -> Option<(Anchor, Breakpoint)> {
11178        let buffer = self
11179            .buffer
11180            .read(cx)
11181            .buffer_for_anchor(breakpoint_position, cx)?;
11182
11183        let enclosing_excerpt = breakpoint_position.excerpt_id;
11184        let buffer_snapshot = buffer.read(cx).snapshot();
11185
11186        let row = buffer_snapshot
11187            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11188            .row;
11189
11190        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11191        let anchor_end = snapshot
11192            .buffer_snapshot()
11193            .anchor_after(Point::new(row, line_len));
11194
11195        self.breakpoint_store
11196            .as_ref()?
11197            .read_with(cx, |breakpoint_store, cx| {
11198                breakpoint_store
11199                    .breakpoints(
11200                        &buffer,
11201                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11202                        &buffer_snapshot,
11203                        cx,
11204                    )
11205                    .next()
11206                    .and_then(|(bp, _)| {
11207                        let breakpoint_row = buffer_snapshot
11208                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11209                            .row;
11210
11211                        if breakpoint_row == row {
11212                            snapshot
11213                                .buffer_snapshot()
11214                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11215                                .map(|position| (position, bp.bp.clone()))
11216                        } else {
11217                            None
11218                        }
11219                    })
11220            })
11221    }
11222
11223    pub fn edit_log_breakpoint(
11224        &mut self,
11225        _: &EditLogBreakpoint,
11226        window: &mut Window,
11227        cx: &mut Context<Self>,
11228    ) {
11229        if self.breakpoint_store.is_none() {
11230            return;
11231        }
11232
11233        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11234            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11235                message: None,
11236                state: BreakpointState::Enabled,
11237                condition: None,
11238                hit_condition: None,
11239            });
11240
11241            self.add_edit_breakpoint_block(
11242                anchor,
11243                &breakpoint,
11244                BreakpointPromptEditAction::Log,
11245                window,
11246                cx,
11247            );
11248        }
11249    }
11250
11251    fn breakpoints_at_cursors(
11252        &self,
11253        window: &mut Window,
11254        cx: &mut Context<Self>,
11255    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11256        let snapshot = self.snapshot(window, cx);
11257        let cursors = self
11258            .selections
11259            .disjoint_anchors_arc()
11260            .iter()
11261            .map(|selection| {
11262                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11263
11264                let breakpoint_position = self
11265                    .breakpoint_at_row(cursor_position.row, window, cx)
11266                    .map(|bp| bp.0)
11267                    .unwrap_or_else(|| {
11268                        snapshot
11269                            .display_snapshot
11270                            .buffer_snapshot()
11271                            .anchor_after(Point::new(cursor_position.row, 0))
11272                    });
11273
11274                let breakpoint = self
11275                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11276                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11277
11278                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11279            })
11280            // 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.
11281            .collect::<HashMap<Anchor, _>>();
11282
11283        cursors.into_iter().collect()
11284    }
11285
11286    pub fn enable_breakpoint(
11287        &mut self,
11288        _: &crate::actions::EnableBreakpoint,
11289        window: &mut Window,
11290        cx: &mut Context<Self>,
11291    ) {
11292        if self.breakpoint_store.is_none() {
11293            return;
11294        }
11295
11296        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11297            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11298                continue;
11299            };
11300            self.edit_breakpoint_at_anchor(
11301                anchor,
11302                breakpoint,
11303                BreakpointEditAction::InvertState,
11304                cx,
11305            );
11306        }
11307    }
11308
11309    pub fn disable_breakpoint(
11310        &mut self,
11311        _: &crate::actions::DisableBreakpoint,
11312        window: &mut Window,
11313        cx: &mut Context<Self>,
11314    ) {
11315        if self.breakpoint_store.is_none() {
11316            return;
11317        }
11318
11319        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11320            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11321                continue;
11322            };
11323            self.edit_breakpoint_at_anchor(
11324                anchor,
11325                breakpoint,
11326                BreakpointEditAction::InvertState,
11327                cx,
11328            );
11329        }
11330    }
11331
11332    pub fn toggle_breakpoint(
11333        &mut self,
11334        _: &crate::actions::ToggleBreakpoint,
11335        window: &mut Window,
11336        cx: &mut Context<Self>,
11337    ) {
11338        if self.breakpoint_store.is_none() {
11339            return;
11340        }
11341
11342        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11343            if let Some(breakpoint) = breakpoint {
11344                self.edit_breakpoint_at_anchor(
11345                    anchor,
11346                    breakpoint,
11347                    BreakpointEditAction::Toggle,
11348                    cx,
11349                );
11350            } else {
11351                self.edit_breakpoint_at_anchor(
11352                    anchor,
11353                    Breakpoint::new_standard(),
11354                    BreakpointEditAction::Toggle,
11355                    cx,
11356                );
11357            }
11358        }
11359    }
11360
11361    pub fn edit_breakpoint_at_anchor(
11362        &mut self,
11363        breakpoint_position: Anchor,
11364        breakpoint: Breakpoint,
11365        edit_action: BreakpointEditAction,
11366        cx: &mut Context<Self>,
11367    ) {
11368        let Some(breakpoint_store) = &self.breakpoint_store else {
11369            return;
11370        };
11371
11372        let Some(buffer) = self
11373            .buffer
11374            .read(cx)
11375            .buffer_for_anchor(breakpoint_position, cx)
11376        else {
11377            return;
11378        };
11379
11380        breakpoint_store.update(cx, |breakpoint_store, cx| {
11381            breakpoint_store.toggle_breakpoint(
11382                buffer,
11383                BreakpointWithPosition {
11384                    position: breakpoint_position.text_anchor,
11385                    bp: breakpoint,
11386                },
11387                edit_action,
11388                cx,
11389            );
11390        });
11391
11392        cx.notify();
11393    }
11394
11395    #[cfg(any(test, feature = "test-support"))]
11396    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11397        self.breakpoint_store.clone()
11398    }
11399
11400    pub fn prepare_restore_change(
11401        &self,
11402        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11403        hunk: &MultiBufferDiffHunk,
11404        cx: &mut App,
11405    ) -> Option<()> {
11406        if hunk.is_created_file() {
11407            return None;
11408        }
11409        let buffer = self.buffer.read(cx);
11410        let diff = buffer.diff_for(hunk.buffer_id)?;
11411        let buffer = buffer.buffer(hunk.buffer_id)?;
11412        let buffer = buffer.read(cx);
11413        let original_text = diff
11414            .read(cx)
11415            .base_text(cx)
11416            .as_rope()
11417            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11418        let buffer_snapshot = buffer.snapshot();
11419        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11420        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11421            probe
11422                .0
11423                .start
11424                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11425                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11426        }) {
11427            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11428            Some(())
11429        } else {
11430            None
11431        }
11432    }
11433
11434    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11435        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11436    }
11437
11438    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11439        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11440    }
11441
11442    fn manipulate_lines<M>(
11443        &mut self,
11444        window: &mut Window,
11445        cx: &mut Context<Self>,
11446        mut manipulate: M,
11447    ) where
11448        M: FnMut(&str) -> LineManipulationResult,
11449    {
11450        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11451
11452        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11453        let buffer = self.buffer.read(cx).snapshot(cx);
11454
11455        let mut edits = Vec::new();
11456
11457        let selections = self.selections.all::<Point>(&display_map);
11458        let mut selections = selections.iter().peekable();
11459        let mut contiguous_row_selections = Vec::new();
11460        let mut new_selections = Vec::new();
11461        let mut added_lines = 0;
11462        let mut removed_lines = 0;
11463
11464        while let Some(selection) = selections.next() {
11465            let (start_row, end_row) = consume_contiguous_rows(
11466                &mut contiguous_row_selections,
11467                selection,
11468                &display_map,
11469                &mut selections,
11470            );
11471
11472            let start_point = Point::new(start_row.0, 0);
11473            let end_point = Point::new(
11474                end_row.previous_row().0,
11475                buffer.line_len(end_row.previous_row()),
11476            );
11477            let text = buffer
11478                .text_for_range(start_point..end_point)
11479                .collect::<String>();
11480
11481            let LineManipulationResult {
11482                new_text,
11483                line_count_before,
11484                line_count_after,
11485            } = manipulate(&text);
11486
11487            edits.push((start_point..end_point, new_text));
11488
11489            // Selections must change based on added and removed line count
11490            let start_row =
11491                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11492            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11493            new_selections.push(Selection {
11494                id: selection.id,
11495                start: start_row,
11496                end: end_row,
11497                goal: SelectionGoal::None,
11498                reversed: selection.reversed,
11499            });
11500
11501            if line_count_after > line_count_before {
11502                added_lines += line_count_after - line_count_before;
11503            } else if line_count_before > line_count_after {
11504                removed_lines += line_count_before - line_count_after;
11505            }
11506        }
11507
11508        self.transact(window, cx, |this, window, cx| {
11509            let buffer = this.buffer.update(cx, |buffer, cx| {
11510                buffer.edit(edits, None, cx);
11511                buffer.snapshot(cx)
11512            });
11513
11514            // Recalculate offsets on newly edited buffer
11515            let new_selections = new_selections
11516                .iter()
11517                .map(|s| {
11518                    let start_point = Point::new(s.start.0, 0);
11519                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11520                    Selection {
11521                        id: s.id,
11522                        start: buffer.point_to_offset(start_point),
11523                        end: buffer.point_to_offset(end_point),
11524                        goal: s.goal,
11525                        reversed: s.reversed,
11526                    }
11527                })
11528                .collect();
11529
11530            this.change_selections(Default::default(), window, cx, |s| {
11531                s.select(new_selections);
11532            });
11533
11534            this.request_autoscroll(Autoscroll::fit(), cx);
11535        });
11536    }
11537
11538    fn manipulate_immutable_lines<Fn>(
11539        &mut self,
11540        window: &mut Window,
11541        cx: &mut Context<Self>,
11542        mut callback: Fn,
11543    ) where
11544        Fn: FnMut(&mut Vec<&str>),
11545    {
11546        self.manipulate_lines(window, cx, |text| {
11547            let mut lines: Vec<&str> = text.split('\n').collect();
11548            let line_count_before = lines.len();
11549
11550            callback(&mut lines);
11551
11552            LineManipulationResult {
11553                new_text: lines.join("\n"),
11554                line_count_before,
11555                line_count_after: lines.len(),
11556            }
11557        });
11558    }
11559
11560    fn manipulate_mutable_lines<Fn>(
11561        &mut self,
11562        window: &mut Window,
11563        cx: &mut Context<Self>,
11564        mut callback: Fn,
11565    ) where
11566        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11567    {
11568        self.manipulate_lines(window, cx, |text| {
11569            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11570            let line_count_before = lines.len();
11571
11572            callback(&mut lines);
11573
11574            LineManipulationResult {
11575                new_text: lines.join("\n"),
11576                line_count_before,
11577                line_count_after: lines.len(),
11578            }
11579        });
11580    }
11581
11582    pub fn convert_indentation_to_spaces(
11583        &mut self,
11584        _: &ConvertIndentationToSpaces,
11585        window: &mut Window,
11586        cx: &mut Context<Self>,
11587    ) {
11588        let settings = self.buffer.read(cx).language_settings(cx);
11589        let tab_size = settings.tab_size.get() as usize;
11590
11591        self.manipulate_mutable_lines(window, cx, |lines| {
11592            // Allocates a reasonably sized scratch buffer once for the whole loop
11593            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11594            // Avoids recomputing spaces that could be inserted many times
11595            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11596                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11597                .collect();
11598
11599            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11600                let mut chars = line.as_ref().chars();
11601                let mut col = 0;
11602                let mut changed = false;
11603
11604                for ch in chars.by_ref() {
11605                    match ch {
11606                        ' ' => {
11607                            reindented_line.push(' ');
11608                            col += 1;
11609                        }
11610                        '\t' => {
11611                            // \t are converted to spaces depending on the current column
11612                            let spaces_len = tab_size - (col % tab_size);
11613                            reindented_line.extend(&space_cache[spaces_len - 1]);
11614                            col += spaces_len;
11615                            changed = true;
11616                        }
11617                        _ => {
11618                            // If we dont append before break, the character is consumed
11619                            reindented_line.push(ch);
11620                            break;
11621                        }
11622                    }
11623                }
11624
11625                if !changed {
11626                    reindented_line.clear();
11627                    continue;
11628                }
11629                // Append the rest of the line and replace old reference with new one
11630                reindented_line.extend(chars);
11631                *line = Cow::Owned(reindented_line.clone());
11632                reindented_line.clear();
11633            }
11634        });
11635    }
11636
11637    pub fn convert_indentation_to_tabs(
11638        &mut self,
11639        _: &ConvertIndentationToTabs,
11640        window: &mut Window,
11641        cx: &mut Context<Self>,
11642    ) {
11643        let settings = self.buffer.read(cx).language_settings(cx);
11644        let tab_size = settings.tab_size.get() as usize;
11645
11646        self.manipulate_mutable_lines(window, cx, |lines| {
11647            // Allocates a reasonably sized buffer once for the whole loop
11648            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11649            // Avoids recomputing spaces that could be inserted many times
11650            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11651                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11652                .collect();
11653
11654            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11655                let mut chars = line.chars();
11656                let mut spaces_count = 0;
11657                let mut first_non_indent_char = None;
11658                let mut changed = false;
11659
11660                for ch in chars.by_ref() {
11661                    match ch {
11662                        ' ' => {
11663                            // Keep track of spaces. Append \t when we reach tab_size
11664                            spaces_count += 1;
11665                            changed = true;
11666                            if spaces_count == tab_size {
11667                                reindented_line.push('\t');
11668                                spaces_count = 0;
11669                            }
11670                        }
11671                        '\t' => {
11672                            reindented_line.push('\t');
11673                            spaces_count = 0;
11674                        }
11675                        _ => {
11676                            // Dont append it yet, we might have remaining spaces
11677                            first_non_indent_char = Some(ch);
11678                            break;
11679                        }
11680                    }
11681                }
11682
11683                if !changed {
11684                    reindented_line.clear();
11685                    continue;
11686                }
11687                // Remaining spaces that didn't make a full tab stop
11688                if spaces_count > 0 {
11689                    reindented_line.extend(&space_cache[spaces_count - 1]);
11690                }
11691                // If we consume an extra character that was not indentation, add it back
11692                if let Some(extra_char) = first_non_indent_char {
11693                    reindented_line.push(extra_char);
11694                }
11695                // Append the rest of the line and replace old reference with new one
11696                reindented_line.extend(chars);
11697                *line = Cow::Owned(reindented_line.clone());
11698                reindented_line.clear();
11699            }
11700        });
11701    }
11702
11703    pub fn convert_to_upper_case(
11704        &mut self,
11705        _: &ConvertToUpperCase,
11706        window: &mut Window,
11707        cx: &mut Context<Self>,
11708    ) {
11709        self.manipulate_text(window, cx, |text| text.to_uppercase())
11710    }
11711
11712    pub fn convert_to_lower_case(
11713        &mut self,
11714        _: &ConvertToLowerCase,
11715        window: &mut Window,
11716        cx: &mut Context<Self>,
11717    ) {
11718        self.manipulate_text(window, cx, |text| text.to_lowercase())
11719    }
11720
11721    pub fn convert_to_title_case(
11722        &mut self,
11723        _: &ConvertToTitleCase,
11724        window: &mut Window,
11725        cx: &mut Context<Self>,
11726    ) {
11727        self.manipulate_text(window, cx, |text| {
11728            text.split('\n')
11729                .map(|line| line.to_case(Case::Title))
11730                .join("\n")
11731        })
11732    }
11733
11734    pub fn convert_to_snake_case(
11735        &mut self,
11736        _: &ConvertToSnakeCase,
11737        window: &mut Window,
11738        cx: &mut Context<Self>,
11739    ) {
11740        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11741    }
11742
11743    pub fn convert_to_kebab_case(
11744        &mut self,
11745        _: &ConvertToKebabCase,
11746        window: &mut Window,
11747        cx: &mut Context<Self>,
11748    ) {
11749        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11750    }
11751
11752    pub fn convert_to_upper_camel_case(
11753        &mut self,
11754        _: &ConvertToUpperCamelCase,
11755        window: &mut Window,
11756        cx: &mut Context<Self>,
11757    ) {
11758        self.manipulate_text(window, cx, |text| {
11759            text.split('\n')
11760                .map(|line| line.to_case(Case::UpperCamel))
11761                .join("\n")
11762        })
11763    }
11764
11765    pub fn convert_to_lower_camel_case(
11766        &mut self,
11767        _: &ConvertToLowerCamelCase,
11768        window: &mut Window,
11769        cx: &mut Context<Self>,
11770    ) {
11771        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11772    }
11773
11774    pub fn convert_to_opposite_case(
11775        &mut self,
11776        _: &ConvertToOppositeCase,
11777        window: &mut Window,
11778        cx: &mut Context<Self>,
11779    ) {
11780        self.manipulate_text(window, cx, |text| {
11781            text.chars()
11782                .fold(String::with_capacity(text.len()), |mut t, c| {
11783                    if c.is_uppercase() {
11784                        t.extend(c.to_lowercase());
11785                    } else {
11786                        t.extend(c.to_uppercase());
11787                    }
11788                    t
11789                })
11790        })
11791    }
11792
11793    pub fn convert_to_sentence_case(
11794        &mut self,
11795        _: &ConvertToSentenceCase,
11796        window: &mut Window,
11797        cx: &mut Context<Self>,
11798    ) {
11799        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11800    }
11801
11802    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11803        self.manipulate_text(window, cx, |text| {
11804            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11805            if has_upper_case_characters {
11806                text.to_lowercase()
11807            } else {
11808                text.to_uppercase()
11809            }
11810        })
11811    }
11812
11813    pub fn convert_to_rot13(
11814        &mut self,
11815        _: &ConvertToRot13,
11816        window: &mut Window,
11817        cx: &mut Context<Self>,
11818    ) {
11819        self.manipulate_text(window, cx, |text| {
11820            text.chars()
11821                .map(|c| match c {
11822                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11823                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11824                    _ => c,
11825                })
11826                .collect()
11827        })
11828    }
11829
11830    pub fn convert_to_rot47(
11831        &mut self,
11832        _: &ConvertToRot47,
11833        window: &mut Window,
11834        cx: &mut Context<Self>,
11835    ) {
11836        self.manipulate_text(window, cx, |text| {
11837            text.chars()
11838                .map(|c| {
11839                    let code_point = c as u32;
11840                    if code_point >= 33 && code_point <= 126 {
11841                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11842                    }
11843                    c
11844                })
11845                .collect()
11846        })
11847    }
11848
11849    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11850    where
11851        Fn: FnMut(&str) -> String,
11852    {
11853        let buffer = self.buffer.read(cx).snapshot(cx);
11854
11855        let mut new_selections = Vec::new();
11856        let mut edits = Vec::new();
11857        let mut selection_adjustment = 0isize;
11858
11859        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11860            let selection_is_empty = selection.is_empty();
11861
11862            let (start, end) = if selection_is_empty {
11863                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11864                (word_range.start, word_range.end)
11865            } else {
11866                (
11867                    buffer.point_to_offset(selection.start),
11868                    buffer.point_to_offset(selection.end),
11869                )
11870            };
11871
11872            let text = buffer.text_for_range(start..end).collect::<String>();
11873            let old_length = text.len() as isize;
11874            let text = callback(&text);
11875
11876            new_selections.push(Selection {
11877                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
11878                end: MultiBufferOffset(
11879                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
11880                ),
11881                goal: SelectionGoal::None,
11882                id: selection.id,
11883                reversed: selection.reversed,
11884            });
11885
11886            selection_adjustment += old_length - text.len() as isize;
11887
11888            edits.push((start..end, text));
11889        }
11890
11891        self.transact(window, cx, |this, window, cx| {
11892            this.buffer.update(cx, |buffer, cx| {
11893                buffer.edit(edits, None, cx);
11894            });
11895
11896            this.change_selections(Default::default(), window, cx, |s| {
11897                s.select(new_selections);
11898            });
11899
11900            this.request_autoscroll(Autoscroll::fit(), cx);
11901        });
11902    }
11903
11904    pub fn move_selection_on_drop(
11905        &mut self,
11906        selection: &Selection<Anchor>,
11907        target: DisplayPoint,
11908        is_cut: bool,
11909        window: &mut Window,
11910        cx: &mut Context<Self>,
11911    ) {
11912        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11913        let buffer = display_map.buffer_snapshot();
11914        let mut edits = Vec::new();
11915        let insert_point = display_map
11916            .clip_point(target, Bias::Left)
11917            .to_point(&display_map);
11918        let text = buffer
11919            .text_for_range(selection.start..selection.end)
11920            .collect::<String>();
11921        if is_cut {
11922            edits.push(((selection.start..selection.end), String::new()));
11923        }
11924        let insert_anchor = buffer.anchor_before(insert_point);
11925        edits.push(((insert_anchor..insert_anchor), text));
11926        let last_edit_start = insert_anchor.bias_left(buffer);
11927        let last_edit_end = insert_anchor.bias_right(buffer);
11928        self.transact(window, cx, |this, window, cx| {
11929            this.buffer.update(cx, |buffer, cx| {
11930                buffer.edit(edits, None, cx);
11931            });
11932            this.change_selections(Default::default(), window, cx, |s| {
11933                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11934            });
11935        });
11936    }
11937
11938    pub fn clear_selection_drag_state(&mut self) {
11939        self.selection_drag_state = SelectionDragState::None;
11940    }
11941
11942    pub fn duplicate(
11943        &mut self,
11944        upwards: bool,
11945        whole_lines: bool,
11946        window: &mut Window,
11947        cx: &mut Context<Self>,
11948    ) {
11949        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11950
11951        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11952        let buffer = display_map.buffer_snapshot();
11953        let selections = self.selections.all::<Point>(&display_map);
11954
11955        let mut edits = Vec::new();
11956        let mut selections_iter = selections.iter().peekable();
11957        while let Some(selection) = selections_iter.next() {
11958            let mut rows = selection.spanned_rows(false, &display_map);
11959            // duplicate line-wise
11960            if whole_lines || selection.start == selection.end {
11961                // Avoid duplicating the same lines twice.
11962                while let Some(next_selection) = selections_iter.peek() {
11963                    let next_rows = next_selection.spanned_rows(false, &display_map);
11964                    if next_rows.start < rows.end {
11965                        rows.end = next_rows.end;
11966                        selections_iter.next().unwrap();
11967                    } else {
11968                        break;
11969                    }
11970                }
11971
11972                // Copy the text from the selected row region and splice it either at the start
11973                // or end of the region.
11974                let start = Point::new(rows.start.0, 0);
11975                let end = Point::new(
11976                    rows.end.previous_row().0,
11977                    buffer.line_len(rows.end.previous_row()),
11978                );
11979
11980                let mut text = buffer.text_for_range(start..end).collect::<String>();
11981
11982                let insert_location = if upwards {
11983                    // When duplicating upward, we need to insert before the current line.
11984                    // If we're on the last line and it doesn't end with a newline,
11985                    // we need to add a newline before the duplicated content.
11986                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11987                        && buffer.max_point().column > 0
11988                        && !text.ends_with('\n');
11989
11990                    if needs_leading_newline {
11991                        text.insert(0, '\n');
11992                        end
11993                    } else {
11994                        text.push('\n');
11995                        Point::new(rows.start.0, 0)
11996                    }
11997                } else {
11998                    text.push('\n');
11999                    start
12000                };
12001                edits.push((insert_location..insert_location, text));
12002            } else {
12003                // duplicate character-wise
12004                let start = selection.start;
12005                let end = selection.end;
12006                let text = buffer.text_for_range(start..end).collect::<String>();
12007                edits.push((selection.end..selection.end, text));
12008            }
12009        }
12010
12011        self.transact(window, cx, |this, window, cx| {
12012            this.buffer.update(cx, |buffer, cx| {
12013                buffer.edit(edits, None, cx);
12014            });
12015
12016            // When duplicating upward with whole lines, move the cursor to the duplicated line
12017            if upwards && whole_lines {
12018                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12019
12020                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12021                    let mut new_ranges = Vec::new();
12022                    let selections = s.all::<Point>(&display_map);
12023                    let mut selections_iter = selections.iter().peekable();
12024
12025                    while let Some(first_selection) = selections_iter.next() {
12026                        // Group contiguous selections together to find the total row span
12027                        let mut group_selections = vec![first_selection];
12028                        let mut rows = first_selection.spanned_rows(false, &display_map);
12029
12030                        while let Some(next_selection) = selections_iter.peek() {
12031                            let next_rows = next_selection.spanned_rows(false, &display_map);
12032                            if next_rows.start < rows.end {
12033                                rows.end = next_rows.end;
12034                                group_selections.push(selections_iter.next().unwrap());
12035                            } else {
12036                                break;
12037                            }
12038                        }
12039
12040                        let row_count = rows.end.0 - rows.start.0;
12041
12042                        // Move all selections in this group up by the total number of duplicated rows
12043                        for selection in group_selections {
12044                            let new_start = Point::new(
12045                                selection.start.row.saturating_sub(row_count),
12046                                selection.start.column,
12047                            );
12048
12049                            let new_end = Point::new(
12050                                selection.end.row.saturating_sub(row_count),
12051                                selection.end.column,
12052                            );
12053
12054                            new_ranges.push(new_start..new_end);
12055                        }
12056                    }
12057
12058                    s.select_ranges(new_ranges);
12059                });
12060            }
12061
12062            this.request_autoscroll(Autoscroll::fit(), cx);
12063        });
12064    }
12065
12066    pub fn duplicate_line_up(
12067        &mut self,
12068        _: &DuplicateLineUp,
12069        window: &mut Window,
12070        cx: &mut Context<Self>,
12071    ) {
12072        self.duplicate(true, true, window, cx);
12073    }
12074
12075    pub fn duplicate_line_down(
12076        &mut self,
12077        _: &DuplicateLineDown,
12078        window: &mut Window,
12079        cx: &mut Context<Self>,
12080    ) {
12081        self.duplicate(false, true, window, cx);
12082    }
12083
12084    pub fn duplicate_selection(
12085        &mut self,
12086        _: &DuplicateSelection,
12087        window: &mut Window,
12088        cx: &mut Context<Self>,
12089    ) {
12090        self.duplicate(false, false, window, cx);
12091    }
12092
12093    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12094        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12095        if self.mode.is_single_line() {
12096            cx.propagate();
12097            return;
12098        }
12099
12100        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12101        let buffer = self.buffer.read(cx).snapshot(cx);
12102
12103        let mut edits = Vec::new();
12104        let mut unfold_ranges = Vec::new();
12105        let mut refold_creases = Vec::new();
12106
12107        let selections = self.selections.all::<Point>(&display_map);
12108        let mut selections = selections.iter().peekable();
12109        let mut contiguous_row_selections = Vec::new();
12110        let mut new_selections = Vec::new();
12111
12112        while let Some(selection) = selections.next() {
12113            // Find all the selections that span a contiguous row range
12114            let (start_row, end_row) = consume_contiguous_rows(
12115                &mut contiguous_row_selections,
12116                selection,
12117                &display_map,
12118                &mut selections,
12119            );
12120
12121            // Move the text spanned by the row range to be before the line preceding the row range
12122            if start_row.0 > 0 {
12123                let range_to_move = Point::new(
12124                    start_row.previous_row().0,
12125                    buffer.line_len(start_row.previous_row()),
12126                )
12127                    ..Point::new(
12128                        end_row.previous_row().0,
12129                        buffer.line_len(end_row.previous_row()),
12130                    );
12131                let insertion_point = display_map
12132                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12133                    .0;
12134
12135                // Don't move lines across excerpts
12136                if buffer
12137                    .excerpt_containing(insertion_point..range_to_move.end)
12138                    .is_some()
12139                {
12140                    let text = buffer
12141                        .text_for_range(range_to_move.clone())
12142                        .flat_map(|s| s.chars())
12143                        .skip(1)
12144                        .chain(['\n'])
12145                        .collect::<String>();
12146
12147                    edits.push((
12148                        buffer.anchor_after(range_to_move.start)
12149                            ..buffer.anchor_before(range_to_move.end),
12150                        String::new(),
12151                    ));
12152                    let insertion_anchor = buffer.anchor_after(insertion_point);
12153                    edits.push((insertion_anchor..insertion_anchor, text));
12154
12155                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12156
12157                    // Move selections up
12158                    new_selections.extend(contiguous_row_selections.drain(..).map(
12159                        |mut selection| {
12160                            selection.start.row -= row_delta;
12161                            selection.end.row -= row_delta;
12162                            selection
12163                        },
12164                    ));
12165
12166                    // Move folds up
12167                    unfold_ranges.push(range_to_move.clone());
12168                    for fold in display_map.folds_in_range(
12169                        buffer.anchor_before(range_to_move.start)
12170                            ..buffer.anchor_after(range_to_move.end),
12171                    ) {
12172                        let mut start = fold.range.start.to_point(&buffer);
12173                        let mut end = fold.range.end.to_point(&buffer);
12174                        start.row -= row_delta;
12175                        end.row -= row_delta;
12176                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12177                    }
12178                }
12179            }
12180
12181            // If we didn't move line(s), preserve the existing selections
12182            new_selections.append(&mut contiguous_row_selections);
12183        }
12184
12185        self.transact(window, cx, |this, window, cx| {
12186            this.unfold_ranges(&unfold_ranges, true, true, cx);
12187            this.buffer.update(cx, |buffer, cx| {
12188                for (range, text) in edits {
12189                    buffer.edit([(range, text)], None, cx);
12190                }
12191            });
12192            this.fold_creases(refold_creases, true, window, cx);
12193            this.change_selections(Default::default(), window, cx, |s| {
12194                s.select(new_selections);
12195            })
12196        });
12197    }
12198
12199    pub fn move_line_down(
12200        &mut self,
12201        _: &MoveLineDown,
12202        window: &mut Window,
12203        cx: &mut Context<Self>,
12204    ) {
12205        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12206        if self.mode.is_single_line() {
12207            cx.propagate();
12208            return;
12209        }
12210
12211        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12212        let buffer = self.buffer.read(cx).snapshot(cx);
12213
12214        let mut edits = Vec::new();
12215        let mut unfold_ranges = Vec::new();
12216        let mut refold_creases = Vec::new();
12217
12218        let selections = self.selections.all::<Point>(&display_map);
12219        let mut selections = selections.iter().peekable();
12220        let mut contiguous_row_selections = Vec::new();
12221        let mut new_selections = Vec::new();
12222
12223        while let Some(selection) = selections.next() {
12224            // Find all the selections that span a contiguous row range
12225            let (start_row, end_row) = consume_contiguous_rows(
12226                &mut contiguous_row_selections,
12227                selection,
12228                &display_map,
12229                &mut selections,
12230            );
12231
12232            // Move the text spanned by the row range to be after the last line of the row range
12233            if end_row.0 <= buffer.max_point().row {
12234                let range_to_move =
12235                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12236                let insertion_point = display_map
12237                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12238                    .0;
12239
12240                // Don't move lines across excerpt boundaries
12241                if buffer
12242                    .excerpt_containing(range_to_move.start..insertion_point)
12243                    .is_some()
12244                {
12245                    let mut text = String::from("\n");
12246                    text.extend(buffer.text_for_range(range_to_move.clone()));
12247                    text.pop(); // Drop trailing newline
12248                    edits.push((
12249                        buffer.anchor_after(range_to_move.start)
12250                            ..buffer.anchor_before(range_to_move.end),
12251                        String::new(),
12252                    ));
12253                    let insertion_anchor = buffer.anchor_after(insertion_point);
12254                    edits.push((insertion_anchor..insertion_anchor, text));
12255
12256                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12257
12258                    // Move selections down
12259                    new_selections.extend(contiguous_row_selections.drain(..).map(
12260                        |mut selection| {
12261                            selection.start.row += row_delta;
12262                            selection.end.row += row_delta;
12263                            selection
12264                        },
12265                    ));
12266
12267                    // Move folds down
12268                    unfold_ranges.push(range_to_move.clone());
12269                    for fold in display_map.folds_in_range(
12270                        buffer.anchor_before(range_to_move.start)
12271                            ..buffer.anchor_after(range_to_move.end),
12272                    ) {
12273                        let mut start = fold.range.start.to_point(&buffer);
12274                        let mut end = fold.range.end.to_point(&buffer);
12275                        start.row += row_delta;
12276                        end.row += row_delta;
12277                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12278                    }
12279                }
12280            }
12281
12282            // If we didn't move line(s), preserve the existing selections
12283            new_selections.append(&mut contiguous_row_selections);
12284        }
12285
12286        self.transact(window, cx, |this, window, cx| {
12287            this.unfold_ranges(&unfold_ranges, true, true, cx);
12288            this.buffer.update(cx, |buffer, cx| {
12289                for (range, text) in edits {
12290                    buffer.edit([(range, text)], None, cx);
12291                }
12292            });
12293            this.fold_creases(refold_creases, true, window, cx);
12294            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12295        });
12296    }
12297
12298    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12299        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12300        let text_layout_details = &self.text_layout_details(window);
12301        self.transact(window, cx, |this, window, cx| {
12302            let edits = this.change_selections(Default::default(), window, cx, |s| {
12303                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12304                s.move_with(|display_map, selection| {
12305                    if !selection.is_empty() {
12306                        return;
12307                    }
12308
12309                    let mut head = selection.head();
12310                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12311                    if head.column() == display_map.line_len(head.row()) {
12312                        transpose_offset = display_map
12313                            .buffer_snapshot()
12314                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12315                    }
12316
12317                    if transpose_offset == MultiBufferOffset(0) {
12318                        return;
12319                    }
12320
12321                    *head.column_mut() += 1;
12322                    head = display_map.clip_point(head, Bias::Right);
12323                    let goal = SelectionGoal::HorizontalPosition(
12324                        display_map
12325                            .x_for_display_point(head, text_layout_details)
12326                            .into(),
12327                    );
12328                    selection.collapse_to(head, goal);
12329
12330                    let transpose_start = display_map
12331                        .buffer_snapshot()
12332                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12333                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12334                        let transpose_end = display_map
12335                            .buffer_snapshot()
12336                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12337                        if let Some(ch) = display_map
12338                            .buffer_snapshot()
12339                            .chars_at(transpose_start)
12340                            .next()
12341                        {
12342                            edits.push((transpose_start..transpose_offset, String::new()));
12343                            edits.push((transpose_end..transpose_end, ch.to_string()));
12344                        }
12345                    }
12346                });
12347                edits
12348            });
12349            this.buffer
12350                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12351            let selections = this
12352                .selections
12353                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12354            this.change_selections(Default::default(), window, cx, |s| {
12355                s.select(selections);
12356            });
12357        });
12358    }
12359
12360    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12361        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12362        if self.mode.is_single_line() {
12363            cx.propagate();
12364            return;
12365        }
12366
12367        self.rewrap_impl(RewrapOptions::default(), cx)
12368    }
12369
12370    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12371        let buffer = self.buffer.read(cx).snapshot(cx);
12372        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12373
12374        #[derive(Clone, Debug, PartialEq)]
12375        enum CommentFormat {
12376            /// single line comment, with prefix for line
12377            Line(String),
12378            /// single line within a block comment, with prefix for line
12379            BlockLine(String),
12380            /// a single line of a block comment that includes the initial delimiter
12381            BlockCommentWithStart(BlockCommentConfig),
12382            /// a single line of a block comment that includes the ending delimiter
12383            BlockCommentWithEnd(BlockCommentConfig),
12384        }
12385
12386        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12387        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12388            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12389                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12390                .peekable();
12391
12392            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12393                row
12394            } else {
12395                return Vec::new();
12396            };
12397
12398            let language_settings = buffer.language_settings_at(selection.head(), cx);
12399            let language_scope = buffer.language_scope_at(selection.head());
12400
12401            let indent_and_prefix_for_row =
12402                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12403                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12404                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12405                        &language_scope
12406                    {
12407                        let indent_end = Point::new(row, indent.len);
12408                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12409                        let line_text_after_indent = buffer
12410                            .text_for_range(indent_end..line_end)
12411                            .collect::<String>();
12412
12413                        let is_within_comment_override = buffer
12414                            .language_scope_at(indent_end)
12415                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12416                        let comment_delimiters = if is_within_comment_override {
12417                            // we are within a comment syntax node, but we don't
12418                            // yet know what kind of comment: block, doc or line
12419                            match (
12420                                language_scope.documentation_comment(),
12421                                language_scope.block_comment(),
12422                            ) {
12423                                (Some(config), _) | (_, Some(config))
12424                                    if buffer.contains_str_at(indent_end, &config.start) =>
12425                                {
12426                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12427                                }
12428                                (Some(config), _) | (_, Some(config))
12429                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12430                                {
12431                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12432                                }
12433                                (Some(config), _) | (_, Some(config))
12434                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12435                                {
12436                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12437                                }
12438                                (_, _) => language_scope
12439                                    .line_comment_prefixes()
12440                                    .iter()
12441                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12442                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12443                            }
12444                        } else {
12445                            // we not in an overridden comment node, but we may
12446                            // be within a non-overridden line comment node
12447                            language_scope
12448                                .line_comment_prefixes()
12449                                .iter()
12450                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12451                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12452                        };
12453
12454                        let rewrap_prefix = language_scope
12455                            .rewrap_prefixes()
12456                            .iter()
12457                            .find_map(|prefix_regex| {
12458                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12459                                    if mat.start() == 0 {
12460                                        Some(mat.as_str().to_string())
12461                                    } else {
12462                                        None
12463                                    }
12464                                })
12465                            })
12466                            .flatten();
12467                        (comment_delimiters, rewrap_prefix)
12468                    } else {
12469                        (None, None)
12470                    };
12471                    (indent, comment_prefix, rewrap_prefix)
12472                };
12473
12474            let mut ranges = Vec::new();
12475            let from_empty_selection = selection.is_empty();
12476
12477            let mut current_range_start = first_row;
12478            let mut prev_row = first_row;
12479            let (
12480                mut current_range_indent,
12481                mut current_range_comment_delimiters,
12482                mut current_range_rewrap_prefix,
12483            ) = indent_and_prefix_for_row(first_row);
12484
12485            for row in non_blank_rows_iter.skip(1) {
12486                let has_paragraph_break = row > prev_row + 1;
12487
12488                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12489                    indent_and_prefix_for_row(row);
12490
12491                let has_indent_change = row_indent != current_range_indent;
12492                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12493
12494                let has_boundary_change = has_comment_change
12495                    || row_rewrap_prefix.is_some()
12496                    || (has_indent_change && current_range_comment_delimiters.is_some());
12497
12498                if has_paragraph_break || has_boundary_change {
12499                    ranges.push((
12500                        language_settings.clone(),
12501                        Point::new(current_range_start, 0)
12502                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12503                        current_range_indent,
12504                        current_range_comment_delimiters.clone(),
12505                        current_range_rewrap_prefix.clone(),
12506                        from_empty_selection,
12507                    ));
12508                    current_range_start = row;
12509                    current_range_indent = row_indent;
12510                    current_range_comment_delimiters = row_comment_delimiters;
12511                    current_range_rewrap_prefix = row_rewrap_prefix;
12512                }
12513                prev_row = row;
12514            }
12515
12516            ranges.push((
12517                language_settings.clone(),
12518                Point::new(current_range_start, 0)
12519                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12520                current_range_indent,
12521                current_range_comment_delimiters,
12522                current_range_rewrap_prefix,
12523                from_empty_selection,
12524            ));
12525
12526            ranges
12527        });
12528
12529        let mut edits = Vec::new();
12530        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12531
12532        for (
12533            language_settings,
12534            wrap_range,
12535            mut indent_size,
12536            comment_prefix,
12537            rewrap_prefix,
12538            from_empty_selection,
12539        ) in wrap_ranges
12540        {
12541            let mut start_row = wrap_range.start.row;
12542            let mut end_row = wrap_range.end.row;
12543
12544            // Skip selections that overlap with a range that has already been rewrapped.
12545            let selection_range = start_row..end_row;
12546            if rewrapped_row_ranges
12547                .iter()
12548                .any(|range| range.overlaps(&selection_range))
12549            {
12550                continue;
12551            }
12552
12553            let tab_size = language_settings.tab_size;
12554
12555            let (line_prefix, inside_comment) = match &comment_prefix {
12556                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12557                    (Some(prefix.as_str()), true)
12558                }
12559                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12560                    (Some(prefix.as_ref()), true)
12561                }
12562                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12563                    start: _,
12564                    end: _,
12565                    prefix,
12566                    tab_size,
12567                })) => {
12568                    indent_size.len += tab_size;
12569                    (Some(prefix.as_ref()), true)
12570                }
12571                None => (None, false),
12572            };
12573            let indent_prefix = indent_size.chars().collect::<String>();
12574            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12575
12576            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12577                RewrapBehavior::InComments => inside_comment,
12578                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12579                RewrapBehavior::Anywhere => true,
12580            };
12581
12582            let should_rewrap = options.override_language_settings
12583                || allow_rewrap_based_on_language
12584                || self.hard_wrap.is_some();
12585            if !should_rewrap {
12586                continue;
12587            }
12588
12589            if from_empty_selection {
12590                'expand_upwards: while start_row > 0 {
12591                    let prev_row = start_row - 1;
12592                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12593                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12594                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12595                    {
12596                        start_row = prev_row;
12597                    } else {
12598                        break 'expand_upwards;
12599                    }
12600                }
12601
12602                'expand_downwards: while end_row < buffer.max_point().row {
12603                    let next_row = end_row + 1;
12604                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12605                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12606                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12607                    {
12608                        end_row = next_row;
12609                    } else {
12610                        break 'expand_downwards;
12611                    }
12612                }
12613            }
12614
12615            let start = Point::new(start_row, 0);
12616            let start_offset = ToOffset::to_offset(&start, &buffer);
12617            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12618            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12619            let mut first_line_delimiter = None;
12620            let mut last_line_delimiter = None;
12621            let Some(lines_without_prefixes) = selection_text
12622                .lines()
12623                .enumerate()
12624                .map(|(ix, line)| {
12625                    let line_trimmed = line.trim_start();
12626                    if rewrap_prefix.is_some() && ix > 0 {
12627                        Ok(line_trimmed)
12628                    } else if let Some(
12629                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12630                            start,
12631                            prefix,
12632                            end,
12633                            tab_size,
12634                        })
12635                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12636                            start,
12637                            prefix,
12638                            end,
12639                            tab_size,
12640                        }),
12641                    ) = &comment_prefix
12642                    {
12643                        let line_trimmed = line_trimmed
12644                            .strip_prefix(start.as_ref())
12645                            .map(|s| {
12646                                let mut indent_size = indent_size;
12647                                indent_size.len -= tab_size;
12648                                let indent_prefix: String = indent_size.chars().collect();
12649                                first_line_delimiter = Some((indent_prefix, start));
12650                                s.trim_start()
12651                            })
12652                            .unwrap_or(line_trimmed);
12653                        let line_trimmed = line_trimmed
12654                            .strip_suffix(end.as_ref())
12655                            .map(|s| {
12656                                last_line_delimiter = Some(end);
12657                                s.trim_end()
12658                            })
12659                            .unwrap_or(line_trimmed);
12660                        let line_trimmed = line_trimmed
12661                            .strip_prefix(prefix.as_ref())
12662                            .unwrap_or(line_trimmed);
12663                        Ok(line_trimmed)
12664                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12665                        line_trimmed.strip_prefix(prefix).with_context(|| {
12666                            format!("line did not start with prefix {prefix:?}: {line:?}")
12667                        })
12668                    } else {
12669                        line_trimmed
12670                            .strip_prefix(&line_prefix.trim_start())
12671                            .with_context(|| {
12672                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12673                            })
12674                    }
12675                })
12676                .collect::<Result<Vec<_>, _>>()
12677                .log_err()
12678            else {
12679                continue;
12680            };
12681
12682            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12683                buffer
12684                    .language_settings_at(Point::new(start_row, 0), cx)
12685                    .preferred_line_length as usize
12686            });
12687
12688            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12689                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12690            } else {
12691                line_prefix.clone()
12692            };
12693
12694            let wrapped_text = {
12695                let mut wrapped_text = wrap_with_prefix(
12696                    line_prefix,
12697                    subsequent_lines_prefix,
12698                    lines_without_prefixes.join("\n"),
12699                    wrap_column,
12700                    tab_size,
12701                    options.preserve_existing_whitespace,
12702                );
12703
12704                if let Some((indent, delimiter)) = first_line_delimiter {
12705                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12706                }
12707                if let Some(last_line) = last_line_delimiter {
12708                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12709                }
12710
12711                wrapped_text
12712            };
12713
12714            // TODO: should always use char-based diff while still supporting cursor behavior that
12715            // matches vim.
12716            let mut diff_options = DiffOptions::default();
12717            if options.override_language_settings {
12718                diff_options.max_word_diff_len = 0;
12719                diff_options.max_word_diff_line_count = 0;
12720            } else {
12721                diff_options.max_word_diff_len = usize::MAX;
12722                diff_options.max_word_diff_line_count = usize::MAX;
12723            }
12724
12725            for (old_range, new_text) in
12726                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12727            {
12728                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12729                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12730                edits.push((edit_start..edit_end, new_text));
12731            }
12732
12733            rewrapped_row_ranges.push(start_row..=end_row);
12734        }
12735
12736        self.buffer
12737            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12738    }
12739
12740    pub fn cut_common(
12741        &mut self,
12742        cut_no_selection_line: bool,
12743        window: &mut Window,
12744        cx: &mut Context<Self>,
12745    ) -> ClipboardItem {
12746        let mut text = String::new();
12747        let buffer = self.buffer.read(cx).snapshot(cx);
12748        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12749        let mut clipboard_selections = Vec::with_capacity(selections.len());
12750        {
12751            let max_point = buffer.max_point();
12752            let mut is_first = true;
12753            let mut prev_selection_was_entire_line = false;
12754            for selection in &mut selections {
12755                let is_entire_line =
12756                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12757                if is_entire_line {
12758                    selection.start = Point::new(selection.start.row, 0);
12759                    if !selection.is_empty() && selection.end.column == 0 {
12760                        selection.end = cmp::min(max_point, selection.end);
12761                    } else {
12762                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12763                    }
12764                    selection.goal = SelectionGoal::None;
12765                }
12766                if is_first {
12767                    is_first = false;
12768                } else if !prev_selection_was_entire_line {
12769                    text += "\n";
12770                }
12771                prev_selection_was_entire_line = is_entire_line;
12772                let mut len = 0;
12773                for chunk in buffer.text_for_range(selection.start..selection.end) {
12774                    text.push_str(chunk);
12775                    len += chunk.len();
12776                }
12777                clipboard_selections.push(ClipboardSelection {
12778                    len,
12779                    is_entire_line,
12780                    first_line_indent: buffer
12781                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12782                        .len,
12783                });
12784            }
12785        }
12786
12787        self.transact(window, cx, |this, window, cx| {
12788            this.change_selections(Default::default(), window, cx, |s| {
12789                s.select(selections);
12790            });
12791            this.insert("", window, cx);
12792        });
12793        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12794    }
12795
12796    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12797        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12798        let item = self.cut_common(true, window, cx);
12799        cx.write_to_clipboard(item);
12800    }
12801
12802    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12803        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12804        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12805            s.move_with(|snapshot, sel| {
12806                if sel.is_empty() {
12807                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12808                }
12809                if sel.is_empty() {
12810                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12811                }
12812            });
12813        });
12814        let item = self.cut_common(false, window, cx);
12815        cx.set_global(KillRing(item))
12816    }
12817
12818    pub fn kill_ring_yank(
12819        &mut self,
12820        _: &KillRingYank,
12821        window: &mut Window,
12822        cx: &mut Context<Self>,
12823    ) {
12824        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12825        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12826            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12827                (kill_ring.text().to_string(), kill_ring.metadata_json())
12828            } else {
12829                return;
12830            }
12831        } else {
12832            return;
12833        };
12834        self.do_paste(&text, metadata, false, window, cx);
12835    }
12836
12837    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12838        self.do_copy(true, cx);
12839    }
12840
12841    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12842        self.do_copy(false, cx);
12843    }
12844
12845    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12846        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12847        let buffer = self.buffer.read(cx).read(cx);
12848        let mut text = String::new();
12849
12850        let mut clipboard_selections = Vec::with_capacity(selections.len());
12851        {
12852            let max_point = buffer.max_point();
12853            let mut is_first = true;
12854            let mut prev_selection_was_entire_line = false;
12855            for selection in &selections {
12856                let mut start = selection.start;
12857                let mut end = selection.end;
12858                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12859                let mut add_trailing_newline = false;
12860                if is_entire_line {
12861                    start = Point::new(start.row, 0);
12862                    let next_line_start = Point::new(end.row + 1, 0);
12863                    if next_line_start <= max_point {
12864                        end = next_line_start;
12865                    } else {
12866                        // We're on the last line without a trailing newline.
12867                        // Copy to the end of the line and add a newline afterwards.
12868                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12869                        add_trailing_newline = true;
12870                    }
12871                }
12872
12873                let mut trimmed_selections = Vec::new();
12874                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12875                    let row = MultiBufferRow(start.row);
12876                    let first_indent = buffer.indent_size_for_line(row);
12877                    if first_indent.len == 0 || start.column > first_indent.len {
12878                        trimmed_selections.push(start..end);
12879                    } else {
12880                        trimmed_selections.push(
12881                            Point::new(row.0, first_indent.len)
12882                                ..Point::new(row.0, buffer.line_len(row)),
12883                        );
12884                        for row in start.row + 1..=end.row {
12885                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12886                            if row == end.row {
12887                                line_len = end.column;
12888                            }
12889                            if line_len == 0 {
12890                                trimmed_selections
12891                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12892                                continue;
12893                            }
12894                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12895                            if row_indent_size.len >= first_indent.len {
12896                                trimmed_selections.push(
12897                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12898                                );
12899                            } else {
12900                                trimmed_selections.clear();
12901                                trimmed_selections.push(start..end);
12902                                break;
12903                            }
12904                        }
12905                    }
12906                } else {
12907                    trimmed_selections.push(start..end);
12908                }
12909
12910                for trimmed_range in trimmed_selections {
12911                    if is_first {
12912                        is_first = false;
12913                    } else if !prev_selection_was_entire_line {
12914                        text += "\n";
12915                    }
12916                    prev_selection_was_entire_line = is_entire_line;
12917                    let mut len = 0;
12918                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12919                        text.push_str(chunk);
12920                        len += chunk.len();
12921                    }
12922                    if add_trailing_newline {
12923                        text.push('\n');
12924                        len += 1;
12925                    }
12926                    clipboard_selections.push(ClipboardSelection {
12927                        len,
12928                        is_entire_line,
12929                        first_line_indent: buffer
12930                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12931                            .len,
12932                    });
12933                }
12934            }
12935        }
12936
12937        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12938            text,
12939            clipboard_selections,
12940        ));
12941    }
12942
12943    pub fn do_paste(
12944        &mut self,
12945        text: &String,
12946        clipboard_selections: Option<Vec<ClipboardSelection>>,
12947        handle_entire_lines: bool,
12948        window: &mut Window,
12949        cx: &mut Context<Self>,
12950    ) {
12951        if self.read_only(cx) {
12952            return;
12953        }
12954
12955        let clipboard_text = Cow::Borrowed(text.as_str());
12956
12957        self.transact(window, cx, |this, window, cx| {
12958            let had_active_edit_prediction = this.has_active_edit_prediction();
12959            let display_map = this.display_snapshot(cx);
12960            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
12961            let cursor_offset = this
12962                .selections
12963                .last::<MultiBufferOffset>(&display_map)
12964                .head();
12965
12966            if let Some(mut clipboard_selections) = clipboard_selections {
12967                let all_selections_were_entire_line =
12968                    clipboard_selections.iter().all(|s| s.is_entire_line);
12969                let first_selection_indent_column =
12970                    clipboard_selections.first().map(|s| s.first_line_indent);
12971                if clipboard_selections.len() != old_selections.len() {
12972                    clipboard_selections.drain(..);
12973                }
12974                let mut auto_indent_on_paste = true;
12975
12976                this.buffer.update(cx, |buffer, cx| {
12977                    let snapshot = buffer.read(cx);
12978                    auto_indent_on_paste = snapshot
12979                        .language_settings_at(cursor_offset, cx)
12980                        .auto_indent_on_paste;
12981
12982                    let mut start_offset = 0;
12983                    let mut edits = Vec::new();
12984                    let mut original_indent_columns = Vec::new();
12985                    for (ix, selection) in old_selections.iter().enumerate() {
12986                        let to_insert;
12987                        let entire_line;
12988                        let original_indent_column;
12989                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12990                            let end_offset = start_offset + clipboard_selection.len;
12991                            to_insert = &clipboard_text[start_offset..end_offset];
12992                            entire_line = clipboard_selection.is_entire_line;
12993                            start_offset = if entire_line {
12994                                end_offset
12995                            } else {
12996                                end_offset + 1
12997                            };
12998                            original_indent_column = Some(clipboard_selection.first_line_indent);
12999                        } else {
13000                            to_insert = &*clipboard_text;
13001                            entire_line = all_selections_were_entire_line;
13002                            original_indent_column = first_selection_indent_column
13003                        }
13004
13005                        let (range, to_insert) =
13006                            if selection.is_empty() && handle_entire_lines && entire_line {
13007                                // If the corresponding selection was empty when this slice of the
13008                                // clipboard text was written, then the entire line containing the
13009                                // selection was copied. If this selection is also currently empty,
13010                                // then paste the line before the current line of the buffer.
13011                                let column = selection.start.to_point(&snapshot).column as usize;
13012                                let line_start = selection.start - column;
13013                                (line_start..line_start, Cow::Borrowed(to_insert))
13014                            } else {
13015                                let language = snapshot.language_at(selection.head());
13016                                let range = selection.range();
13017                                if let Some(language) = language
13018                                    && language.name() == "Markdown".into()
13019                                {
13020                                    edit_for_markdown_paste(
13021                                        &snapshot,
13022                                        range,
13023                                        to_insert,
13024                                        url::Url::parse(to_insert).ok(),
13025                                    )
13026                                } else {
13027                                    (range, Cow::Borrowed(to_insert))
13028                                }
13029                            };
13030
13031                        edits.push((range, to_insert));
13032                        original_indent_columns.push(original_indent_column);
13033                    }
13034                    drop(snapshot);
13035
13036                    buffer.edit(
13037                        edits,
13038                        if auto_indent_on_paste {
13039                            Some(AutoindentMode::Block {
13040                                original_indent_columns,
13041                            })
13042                        } else {
13043                            None
13044                        },
13045                        cx,
13046                    );
13047                });
13048
13049                let selections = this
13050                    .selections
13051                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13052                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13053            } else {
13054                let url = url::Url::parse(&clipboard_text).ok();
13055
13056                let auto_indent_mode = if !clipboard_text.is_empty() {
13057                    Some(AutoindentMode::Block {
13058                        original_indent_columns: Vec::new(),
13059                    })
13060                } else {
13061                    None
13062                };
13063
13064                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13065                    let snapshot = buffer.snapshot(cx);
13066
13067                    let anchors = old_selections
13068                        .iter()
13069                        .map(|s| {
13070                            let anchor = snapshot.anchor_after(s.head());
13071                            s.map(|_| anchor)
13072                        })
13073                        .collect::<Vec<_>>();
13074
13075                    let mut edits = Vec::new();
13076
13077                    for selection in old_selections.iter() {
13078                        let language = snapshot.language_at(selection.head());
13079                        let range = selection.range();
13080
13081                        let (edit_range, edit_text) = if let Some(language) = language
13082                            && language.name() == "Markdown".into()
13083                        {
13084                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13085                        } else {
13086                            (range, clipboard_text.clone())
13087                        };
13088
13089                        edits.push((edit_range, edit_text));
13090                    }
13091
13092                    drop(snapshot);
13093                    buffer.edit(edits, auto_indent_mode, cx);
13094
13095                    anchors
13096                });
13097
13098                this.change_selections(Default::default(), window, cx, |s| {
13099                    s.select_anchors(selection_anchors);
13100                });
13101            }
13102
13103            //   🤔                 |    ..     | show_in_menu |
13104            // | ..                  |   true        true
13105            // | had_edit_prediction |   false       true
13106
13107            let trigger_in_words =
13108                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13109
13110            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13111        });
13112    }
13113
13114    pub fn diff_clipboard_with_selection(
13115        &mut self,
13116        _: &DiffClipboardWithSelection,
13117        window: &mut Window,
13118        cx: &mut Context<Self>,
13119    ) {
13120        let selections = self
13121            .selections
13122            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13123
13124        if selections.is_empty() {
13125            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13126            return;
13127        };
13128
13129        let clipboard_text = match cx.read_from_clipboard() {
13130            Some(item) => match item.entries().first() {
13131                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13132                _ => None,
13133            },
13134            None => None,
13135        };
13136
13137        let Some(clipboard_text) = clipboard_text else {
13138            log::warn!("Clipboard doesn't contain text.");
13139            return;
13140        };
13141
13142        window.dispatch_action(
13143            Box::new(DiffClipboardWithSelectionData {
13144                clipboard_text,
13145                editor: cx.entity(),
13146            }),
13147            cx,
13148        );
13149    }
13150
13151    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13152        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13153        if let Some(item) = cx.read_from_clipboard() {
13154            let entries = item.entries();
13155
13156            match entries.first() {
13157                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13158                // of all the pasted entries.
13159                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13160                    .do_paste(
13161                        clipboard_string.text(),
13162                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13163                        true,
13164                        window,
13165                        cx,
13166                    ),
13167                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13168            }
13169        }
13170    }
13171
13172    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13173        if self.read_only(cx) {
13174            return;
13175        }
13176
13177        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13178
13179        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13180            if let Some((selections, _)) =
13181                self.selection_history.transaction(transaction_id).cloned()
13182            {
13183                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13184                    s.select_anchors(selections.to_vec());
13185                });
13186            } else {
13187                log::error!(
13188                    "No entry in selection_history found for undo. \
13189                     This may correspond to a bug where undo does not update the selection. \
13190                     If this is occurring, please add details to \
13191                     https://github.com/zed-industries/zed/issues/22692"
13192                );
13193            }
13194            self.request_autoscroll(Autoscroll::fit(), cx);
13195            self.unmark_text(window, cx);
13196            self.refresh_edit_prediction(true, false, window, cx);
13197            cx.emit(EditorEvent::Edited { transaction_id });
13198            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13199        }
13200    }
13201
13202    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13203        if self.read_only(cx) {
13204            return;
13205        }
13206
13207        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13208
13209        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13210            if let Some((_, Some(selections))) =
13211                self.selection_history.transaction(transaction_id).cloned()
13212            {
13213                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13214                    s.select_anchors(selections.to_vec());
13215                });
13216            } else {
13217                log::error!(
13218                    "No entry in selection_history found for redo. \
13219                     This may correspond to a bug where undo does not update the selection. \
13220                     If this is occurring, please add details to \
13221                     https://github.com/zed-industries/zed/issues/22692"
13222                );
13223            }
13224            self.request_autoscroll(Autoscroll::fit(), cx);
13225            self.unmark_text(window, cx);
13226            self.refresh_edit_prediction(true, false, window, cx);
13227            cx.emit(EditorEvent::Edited { transaction_id });
13228        }
13229    }
13230
13231    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13232        self.buffer
13233            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13234    }
13235
13236    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13237        self.buffer
13238            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13239    }
13240
13241    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13243        self.change_selections(Default::default(), window, cx, |s| {
13244            s.move_with(|map, selection| {
13245                let cursor = if selection.is_empty() {
13246                    movement::left(map, selection.start)
13247                } else {
13248                    selection.start
13249                };
13250                selection.collapse_to(cursor, SelectionGoal::None);
13251            });
13252        })
13253    }
13254
13255    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13256        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13257        self.change_selections(Default::default(), window, cx, |s| {
13258            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13259        })
13260    }
13261
13262    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13264        self.change_selections(Default::default(), window, cx, |s| {
13265            s.move_with(|map, selection| {
13266                let cursor = if selection.is_empty() {
13267                    movement::right(map, selection.end)
13268                } else {
13269                    selection.end
13270                };
13271                selection.collapse_to(cursor, SelectionGoal::None)
13272            });
13273        })
13274    }
13275
13276    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13277        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13278        self.change_selections(Default::default(), window, cx, |s| {
13279            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13280        });
13281    }
13282
13283    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13284        if self.take_rename(true, window, cx).is_some() {
13285            return;
13286        }
13287
13288        if self.mode.is_single_line() {
13289            cx.propagate();
13290            return;
13291        }
13292
13293        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13294
13295        let text_layout_details = &self.text_layout_details(window);
13296        let selection_count = self.selections.count();
13297        let first_selection = self.selections.first_anchor();
13298
13299        self.change_selections(Default::default(), window, cx, |s| {
13300            s.move_with(|map, selection| {
13301                if !selection.is_empty() {
13302                    selection.goal = SelectionGoal::None;
13303                }
13304                let (cursor, goal) = movement::up(
13305                    map,
13306                    selection.start,
13307                    selection.goal,
13308                    false,
13309                    text_layout_details,
13310                );
13311                selection.collapse_to(cursor, goal);
13312            });
13313        });
13314
13315        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13316        {
13317            cx.propagate();
13318        }
13319    }
13320
13321    pub fn move_up_by_lines(
13322        &mut self,
13323        action: &MoveUpByLines,
13324        window: &mut Window,
13325        cx: &mut Context<Self>,
13326    ) {
13327        if self.take_rename(true, window, cx).is_some() {
13328            return;
13329        }
13330
13331        if self.mode.is_single_line() {
13332            cx.propagate();
13333            return;
13334        }
13335
13336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13337
13338        let text_layout_details = &self.text_layout_details(window);
13339
13340        self.change_selections(Default::default(), window, cx, |s| {
13341            s.move_with(|map, selection| {
13342                if !selection.is_empty() {
13343                    selection.goal = SelectionGoal::None;
13344                }
13345                let (cursor, goal) = movement::up_by_rows(
13346                    map,
13347                    selection.start,
13348                    action.lines,
13349                    selection.goal,
13350                    false,
13351                    text_layout_details,
13352                );
13353                selection.collapse_to(cursor, goal);
13354            });
13355        })
13356    }
13357
13358    pub fn move_down_by_lines(
13359        &mut self,
13360        action: &MoveDownByLines,
13361        window: &mut Window,
13362        cx: &mut Context<Self>,
13363    ) {
13364        if self.take_rename(true, window, cx).is_some() {
13365            return;
13366        }
13367
13368        if self.mode.is_single_line() {
13369            cx.propagate();
13370            return;
13371        }
13372
13373        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13374
13375        let text_layout_details = &self.text_layout_details(window);
13376
13377        self.change_selections(Default::default(), window, cx, |s| {
13378            s.move_with(|map, selection| {
13379                if !selection.is_empty() {
13380                    selection.goal = SelectionGoal::None;
13381                }
13382                let (cursor, goal) = movement::down_by_rows(
13383                    map,
13384                    selection.start,
13385                    action.lines,
13386                    selection.goal,
13387                    false,
13388                    text_layout_details,
13389                );
13390                selection.collapse_to(cursor, goal);
13391            });
13392        })
13393    }
13394
13395    pub fn select_down_by_lines(
13396        &mut self,
13397        action: &SelectDownByLines,
13398        window: &mut Window,
13399        cx: &mut Context<Self>,
13400    ) {
13401        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13402        let text_layout_details = &self.text_layout_details(window);
13403        self.change_selections(Default::default(), window, cx, |s| {
13404            s.move_heads_with(|map, head, goal| {
13405                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13406            })
13407        })
13408    }
13409
13410    pub fn select_up_by_lines(
13411        &mut self,
13412        action: &SelectUpByLines,
13413        window: &mut Window,
13414        cx: &mut Context<Self>,
13415    ) {
13416        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13417        let text_layout_details = &self.text_layout_details(window);
13418        self.change_selections(Default::default(), window, cx, |s| {
13419            s.move_heads_with(|map, head, goal| {
13420                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13421            })
13422        })
13423    }
13424
13425    pub fn select_page_up(
13426        &mut self,
13427        _: &SelectPageUp,
13428        window: &mut Window,
13429        cx: &mut Context<Self>,
13430    ) {
13431        let Some(row_count) = self.visible_row_count() else {
13432            return;
13433        };
13434
13435        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13436
13437        let text_layout_details = &self.text_layout_details(window);
13438
13439        self.change_selections(Default::default(), window, cx, |s| {
13440            s.move_heads_with(|map, head, goal| {
13441                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13442            })
13443        })
13444    }
13445
13446    pub fn move_page_up(
13447        &mut self,
13448        action: &MovePageUp,
13449        window: &mut Window,
13450        cx: &mut Context<Self>,
13451    ) {
13452        if self.take_rename(true, window, cx).is_some() {
13453            return;
13454        }
13455
13456        if self
13457            .context_menu
13458            .borrow_mut()
13459            .as_mut()
13460            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13461            .unwrap_or(false)
13462        {
13463            return;
13464        }
13465
13466        if matches!(self.mode, EditorMode::SingleLine) {
13467            cx.propagate();
13468            return;
13469        }
13470
13471        let Some(row_count) = self.visible_row_count() else {
13472            return;
13473        };
13474
13475        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13476
13477        let effects = if action.center_cursor {
13478            SelectionEffects::scroll(Autoscroll::center())
13479        } else {
13480            SelectionEffects::default()
13481        };
13482
13483        let text_layout_details = &self.text_layout_details(window);
13484
13485        self.change_selections(effects, window, cx, |s| {
13486            s.move_with(|map, selection| {
13487                if !selection.is_empty() {
13488                    selection.goal = SelectionGoal::None;
13489                }
13490                let (cursor, goal) = movement::up_by_rows(
13491                    map,
13492                    selection.end,
13493                    row_count,
13494                    selection.goal,
13495                    false,
13496                    text_layout_details,
13497                );
13498                selection.collapse_to(cursor, goal);
13499            });
13500        });
13501    }
13502
13503    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13504        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13505        let text_layout_details = &self.text_layout_details(window);
13506        self.change_selections(Default::default(), window, cx, |s| {
13507            s.move_heads_with(|map, head, goal| {
13508                movement::up(map, head, goal, false, text_layout_details)
13509            })
13510        })
13511    }
13512
13513    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13514        self.take_rename(true, window, cx);
13515
13516        if self.mode.is_single_line() {
13517            cx.propagate();
13518            return;
13519        }
13520
13521        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13522
13523        let text_layout_details = &self.text_layout_details(window);
13524        let selection_count = self.selections.count();
13525        let first_selection = self.selections.first_anchor();
13526
13527        self.change_selections(Default::default(), window, cx, |s| {
13528            s.move_with(|map, selection| {
13529                if !selection.is_empty() {
13530                    selection.goal = SelectionGoal::None;
13531                }
13532                let (cursor, goal) = movement::down(
13533                    map,
13534                    selection.end,
13535                    selection.goal,
13536                    false,
13537                    text_layout_details,
13538                );
13539                selection.collapse_to(cursor, goal);
13540            });
13541        });
13542
13543        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13544        {
13545            cx.propagate();
13546        }
13547    }
13548
13549    pub fn select_page_down(
13550        &mut self,
13551        _: &SelectPageDown,
13552        window: &mut Window,
13553        cx: &mut Context<Self>,
13554    ) {
13555        let Some(row_count) = self.visible_row_count() else {
13556            return;
13557        };
13558
13559        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13560
13561        let text_layout_details = &self.text_layout_details(window);
13562
13563        self.change_selections(Default::default(), window, cx, |s| {
13564            s.move_heads_with(|map, head, goal| {
13565                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13566            })
13567        })
13568    }
13569
13570    pub fn move_page_down(
13571        &mut self,
13572        action: &MovePageDown,
13573        window: &mut Window,
13574        cx: &mut Context<Self>,
13575    ) {
13576        if self.take_rename(true, window, cx).is_some() {
13577            return;
13578        }
13579
13580        if self
13581            .context_menu
13582            .borrow_mut()
13583            .as_mut()
13584            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13585            .unwrap_or(false)
13586        {
13587            return;
13588        }
13589
13590        if matches!(self.mode, EditorMode::SingleLine) {
13591            cx.propagate();
13592            return;
13593        }
13594
13595        let Some(row_count) = self.visible_row_count() else {
13596            return;
13597        };
13598
13599        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13600
13601        let effects = if action.center_cursor {
13602            SelectionEffects::scroll(Autoscroll::center())
13603        } else {
13604            SelectionEffects::default()
13605        };
13606
13607        let text_layout_details = &self.text_layout_details(window);
13608        self.change_selections(effects, window, cx, |s| {
13609            s.move_with(|map, selection| {
13610                if !selection.is_empty() {
13611                    selection.goal = SelectionGoal::None;
13612                }
13613                let (cursor, goal) = movement::down_by_rows(
13614                    map,
13615                    selection.end,
13616                    row_count,
13617                    selection.goal,
13618                    false,
13619                    text_layout_details,
13620                );
13621                selection.collapse_to(cursor, goal);
13622            });
13623        });
13624    }
13625
13626    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13627        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13628        let text_layout_details = &self.text_layout_details(window);
13629        self.change_selections(Default::default(), window, cx, |s| {
13630            s.move_heads_with(|map, head, goal| {
13631                movement::down(map, head, goal, false, text_layout_details)
13632            })
13633        });
13634    }
13635
13636    pub fn context_menu_first(
13637        &mut self,
13638        _: &ContextMenuFirst,
13639        window: &mut Window,
13640        cx: &mut Context<Self>,
13641    ) {
13642        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13643            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13644        }
13645    }
13646
13647    pub fn context_menu_prev(
13648        &mut self,
13649        _: &ContextMenuPrevious,
13650        window: &mut Window,
13651        cx: &mut Context<Self>,
13652    ) {
13653        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13654            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13655        }
13656    }
13657
13658    pub fn context_menu_next(
13659        &mut self,
13660        _: &ContextMenuNext,
13661        window: &mut Window,
13662        cx: &mut Context<Self>,
13663    ) {
13664        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13665            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13666        }
13667    }
13668
13669    pub fn context_menu_last(
13670        &mut self,
13671        _: &ContextMenuLast,
13672        window: &mut Window,
13673        cx: &mut Context<Self>,
13674    ) {
13675        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13676            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13677        }
13678    }
13679
13680    pub fn signature_help_prev(
13681        &mut self,
13682        _: &SignatureHelpPrevious,
13683        _: &mut Window,
13684        cx: &mut Context<Self>,
13685    ) {
13686        if let Some(popover) = self.signature_help_state.popover_mut() {
13687            if popover.current_signature == 0 {
13688                popover.current_signature = popover.signatures.len() - 1;
13689            } else {
13690                popover.current_signature -= 1;
13691            }
13692            cx.notify();
13693        }
13694    }
13695
13696    pub fn signature_help_next(
13697        &mut self,
13698        _: &SignatureHelpNext,
13699        _: &mut Window,
13700        cx: &mut Context<Self>,
13701    ) {
13702        if let Some(popover) = self.signature_help_state.popover_mut() {
13703            if popover.current_signature + 1 == popover.signatures.len() {
13704                popover.current_signature = 0;
13705            } else {
13706                popover.current_signature += 1;
13707            }
13708            cx.notify();
13709        }
13710    }
13711
13712    pub fn move_to_previous_word_start(
13713        &mut self,
13714        _: &MoveToPreviousWordStart,
13715        window: &mut Window,
13716        cx: &mut Context<Self>,
13717    ) {
13718        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13719        self.change_selections(Default::default(), window, cx, |s| {
13720            s.move_cursors_with(|map, head, _| {
13721                (
13722                    movement::previous_word_start(map, head),
13723                    SelectionGoal::None,
13724                )
13725            });
13726        })
13727    }
13728
13729    pub fn move_to_previous_subword_start(
13730        &mut self,
13731        _: &MoveToPreviousSubwordStart,
13732        window: &mut Window,
13733        cx: &mut Context<Self>,
13734    ) {
13735        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13736        self.change_selections(Default::default(), window, cx, |s| {
13737            s.move_cursors_with(|map, head, _| {
13738                (
13739                    movement::previous_subword_start(map, head),
13740                    SelectionGoal::None,
13741                )
13742            });
13743        })
13744    }
13745
13746    pub fn select_to_previous_word_start(
13747        &mut self,
13748        _: &SelectToPreviousWordStart,
13749        window: &mut Window,
13750        cx: &mut Context<Self>,
13751    ) {
13752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13753        self.change_selections(Default::default(), window, cx, |s| {
13754            s.move_heads_with(|map, head, _| {
13755                (
13756                    movement::previous_word_start(map, head),
13757                    SelectionGoal::None,
13758                )
13759            });
13760        })
13761    }
13762
13763    pub fn select_to_previous_subword_start(
13764        &mut self,
13765        _: &SelectToPreviousSubwordStart,
13766        window: &mut Window,
13767        cx: &mut Context<Self>,
13768    ) {
13769        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13770        self.change_selections(Default::default(), window, cx, |s| {
13771            s.move_heads_with(|map, head, _| {
13772                (
13773                    movement::previous_subword_start(map, head),
13774                    SelectionGoal::None,
13775                )
13776            });
13777        })
13778    }
13779
13780    pub fn delete_to_previous_word_start(
13781        &mut self,
13782        action: &DeleteToPreviousWordStart,
13783        window: &mut Window,
13784        cx: &mut Context<Self>,
13785    ) {
13786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13787        self.transact(window, cx, |this, window, cx| {
13788            this.select_autoclose_pair(window, cx);
13789            this.change_selections(Default::default(), window, cx, |s| {
13790                s.move_with(|map, selection| {
13791                    if selection.is_empty() {
13792                        let mut cursor = if action.ignore_newlines {
13793                            movement::previous_word_start(map, selection.head())
13794                        } else {
13795                            movement::previous_word_start_or_newline(map, selection.head())
13796                        };
13797                        cursor = movement::adjust_greedy_deletion(
13798                            map,
13799                            selection.head(),
13800                            cursor,
13801                            action.ignore_brackets,
13802                        );
13803                        selection.set_head(cursor, SelectionGoal::None);
13804                    }
13805                });
13806            });
13807            this.insert("", window, cx);
13808        });
13809    }
13810
13811    pub fn delete_to_previous_subword_start(
13812        &mut self,
13813        _: &DeleteToPreviousSubwordStart,
13814        window: &mut Window,
13815        cx: &mut Context<Self>,
13816    ) {
13817        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13818        self.transact(window, cx, |this, window, cx| {
13819            this.select_autoclose_pair(window, cx);
13820            this.change_selections(Default::default(), window, cx, |s| {
13821                s.move_with(|map, selection| {
13822                    if selection.is_empty() {
13823                        let mut cursor = movement::previous_subword_start(map, selection.head());
13824                        cursor =
13825                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13826                        selection.set_head(cursor, SelectionGoal::None);
13827                    }
13828                });
13829            });
13830            this.insert("", window, cx);
13831        });
13832    }
13833
13834    pub fn move_to_next_word_end(
13835        &mut self,
13836        _: &MoveToNextWordEnd,
13837        window: &mut Window,
13838        cx: &mut Context<Self>,
13839    ) {
13840        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13841        self.change_selections(Default::default(), window, cx, |s| {
13842            s.move_cursors_with(|map, head, _| {
13843                (movement::next_word_end(map, head), SelectionGoal::None)
13844            });
13845        })
13846    }
13847
13848    pub fn move_to_next_subword_end(
13849        &mut self,
13850        _: &MoveToNextSubwordEnd,
13851        window: &mut Window,
13852        cx: &mut Context<Self>,
13853    ) {
13854        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13855        self.change_selections(Default::default(), window, cx, |s| {
13856            s.move_cursors_with(|map, head, _| {
13857                (movement::next_subword_end(map, head), SelectionGoal::None)
13858            });
13859        })
13860    }
13861
13862    pub fn select_to_next_word_end(
13863        &mut self,
13864        _: &SelectToNextWordEnd,
13865        window: &mut Window,
13866        cx: &mut Context<Self>,
13867    ) {
13868        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13869        self.change_selections(Default::default(), window, cx, |s| {
13870            s.move_heads_with(|map, head, _| {
13871                (movement::next_word_end(map, head), SelectionGoal::None)
13872            });
13873        })
13874    }
13875
13876    pub fn select_to_next_subword_end(
13877        &mut self,
13878        _: &SelectToNextSubwordEnd,
13879        window: &mut Window,
13880        cx: &mut Context<Self>,
13881    ) {
13882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13883        self.change_selections(Default::default(), window, cx, |s| {
13884            s.move_heads_with(|map, head, _| {
13885                (movement::next_subword_end(map, head), SelectionGoal::None)
13886            });
13887        })
13888    }
13889
13890    pub fn delete_to_next_word_end(
13891        &mut self,
13892        action: &DeleteToNextWordEnd,
13893        window: &mut Window,
13894        cx: &mut Context<Self>,
13895    ) {
13896        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13897        self.transact(window, cx, |this, window, cx| {
13898            this.change_selections(Default::default(), window, cx, |s| {
13899                s.move_with(|map, selection| {
13900                    if selection.is_empty() {
13901                        let mut cursor = if action.ignore_newlines {
13902                            movement::next_word_end(map, selection.head())
13903                        } else {
13904                            movement::next_word_end_or_newline(map, selection.head())
13905                        };
13906                        cursor = movement::adjust_greedy_deletion(
13907                            map,
13908                            selection.head(),
13909                            cursor,
13910                            action.ignore_brackets,
13911                        );
13912                        selection.set_head(cursor, SelectionGoal::None);
13913                    }
13914                });
13915            });
13916            this.insert("", window, cx);
13917        });
13918    }
13919
13920    pub fn delete_to_next_subword_end(
13921        &mut self,
13922        _: &DeleteToNextSubwordEnd,
13923        window: &mut Window,
13924        cx: &mut Context<Self>,
13925    ) {
13926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13927        self.transact(window, cx, |this, window, cx| {
13928            this.change_selections(Default::default(), window, cx, |s| {
13929                s.move_with(|map, selection| {
13930                    if selection.is_empty() {
13931                        let mut cursor = movement::next_subword_end(map, selection.head());
13932                        cursor =
13933                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13934                        selection.set_head(cursor, SelectionGoal::None);
13935                    }
13936                });
13937            });
13938            this.insert("", window, cx);
13939        });
13940    }
13941
13942    pub fn move_to_beginning_of_line(
13943        &mut self,
13944        action: &MoveToBeginningOfLine,
13945        window: &mut Window,
13946        cx: &mut Context<Self>,
13947    ) {
13948        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13949        self.change_selections(Default::default(), window, cx, |s| {
13950            s.move_cursors_with(|map, head, _| {
13951                (
13952                    movement::indented_line_beginning(
13953                        map,
13954                        head,
13955                        action.stop_at_soft_wraps,
13956                        action.stop_at_indent,
13957                    ),
13958                    SelectionGoal::None,
13959                )
13960            });
13961        })
13962    }
13963
13964    pub fn select_to_beginning_of_line(
13965        &mut self,
13966        action: &SelectToBeginningOfLine,
13967        window: &mut Window,
13968        cx: &mut Context<Self>,
13969    ) {
13970        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13971        self.change_selections(Default::default(), window, cx, |s| {
13972            s.move_heads_with(|map, head, _| {
13973                (
13974                    movement::indented_line_beginning(
13975                        map,
13976                        head,
13977                        action.stop_at_soft_wraps,
13978                        action.stop_at_indent,
13979                    ),
13980                    SelectionGoal::None,
13981                )
13982            });
13983        });
13984    }
13985
13986    pub fn delete_to_beginning_of_line(
13987        &mut self,
13988        action: &DeleteToBeginningOfLine,
13989        window: &mut Window,
13990        cx: &mut Context<Self>,
13991    ) {
13992        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13993        self.transact(window, cx, |this, window, cx| {
13994            this.change_selections(Default::default(), window, cx, |s| {
13995                s.move_with(|_, selection| {
13996                    selection.reversed = true;
13997                });
13998            });
13999
14000            this.select_to_beginning_of_line(
14001                &SelectToBeginningOfLine {
14002                    stop_at_soft_wraps: false,
14003                    stop_at_indent: action.stop_at_indent,
14004                },
14005                window,
14006                cx,
14007            );
14008            this.backspace(&Backspace, window, cx);
14009        });
14010    }
14011
14012    pub fn move_to_end_of_line(
14013        &mut self,
14014        action: &MoveToEndOfLine,
14015        window: &mut Window,
14016        cx: &mut Context<Self>,
14017    ) {
14018        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14019        self.change_selections(Default::default(), window, cx, |s| {
14020            s.move_cursors_with(|map, head, _| {
14021                (
14022                    movement::line_end(map, head, action.stop_at_soft_wraps),
14023                    SelectionGoal::None,
14024                )
14025            });
14026        })
14027    }
14028
14029    pub fn select_to_end_of_line(
14030        &mut self,
14031        action: &SelectToEndOfLine,
14032        window: &mut Window,
14033        cx: &mut Context<Self>,
14034    ) {
14035        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14036        self.change_selections(Default::default(), window, cx, |s| {
14037            s.move_heads_with(|map, head, _| {
14038                (
14039                    movement::line_end(map, head, action.stop_at_soft_wraps),
14040                    SelectionGoal::None,
14041                )
14042            });
14043        })
14044    }
14045
14046    pub fn delete_to_end_of_line(
14047        &mut self,
14048        _: &DeleteToEndOfLine,
14049        window: &mut Window,
14050        cx: &mut Context<Self>,
14051    ) {
14052        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14053        self.transact(window, cx, |this, window, cx| {
14054            this.select_to_end_of_line(
14055                &SelectToEndOfLine {
14056                    stop_at_soft_wraps: false,
14057                },
14058                window,
14059                cx,
14060            );
14061            this.delete(&Delete, window, cx);
14062        });
14063    }
14064
14065    pub fn cut_to_end_of_line(
14066        &mut self,
14067        action: &CutToEndOfLine,
14068        window: &mut Window,
14069        cx: &mut Context<Self>,
14070    ) {
14071        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14072        self.transact(window, cx, |this, window, cx| {
14073            this.select_to_end_of_line(
14074                &SelectToEndOfLine {
14075                    stop_at_soft_wraps: false,
14076                },
14077                window,
14078                cx,
14079            );
14080            if !action.stop_at_newlines {
14081                this.change_selections(Default::default(), window, cx, |s| {
14082                    s.move_with(|_, sel| {
14083                        if sel.is_empty() {
14084                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14085                        }
14086                    });
14087                });
14088            }
14089            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14090            let item = this.cut_common(false, window, cx);
14091            cx.write_to_clipboard(item);
14092        });
14093    }
14094
14095    pub fn move_to_start_of_paragraph(
14096        &mut self,
14097        _: &MoveToStartOfParagraph,
14098        window: &mut Window,
14099        cx: &mut Context<Self>,
14100    ) {
14101        if matches!(self.mode, EditorMode::SingleLine) {
14102            cx.propagate();
14103            return;
14104        }
14105        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14106        self.change_selections(Default::default(), window, cx, |s| {
14107            s.move_with(|map, selection| {
14108                selection.collapse_to(
14109                    movement::start_of_paragraph(map, selection.head(), 1),
14110                    SelectionGoal::None,
14111                )
14112            });
14113        })
14114    }
14115
14116    pub fn move_to_end_of_paragraph(
14117        &mut self,
14118        _: &MoveToEndOfParagraph,
14119        window: &mut Window,
14120        cx: &mut Context<Self>,
14121    ) {
14122        if matches!(self.mode, EditorMode::SingleLine) {
14123            cx.propagate();
14124            return;
14125        }
14126        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14127        self.change_selections(Default::default(), window, cx, |s| {
14128            s.move_with(|map, selection| {
14129                selection.collapse_to(
14130                    movement::end_of_paragraph(map, selection.head(), 1),
14131                    SelectionGoal::None,
14132                )
14133            });
14134        })
14135    }
14136
14137    pub fn select_to_start_of_paragraph(
14138        &mut self,
14139        _: &SelectToStartOfParagraph,
14140        window: &mut Window,
14141        cx: &mut Context<Self>,
14142    ) {
14143        if matches!(self.mode, EditorMode::SingleLine) {
14144            cx.propagate();
14145            return;
14146        }
14147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14148        self.change_selections(Default::default(), window, cx, |s| {
14149            s.move_heads_with(|map, head, _| {
14150                (
14151                    movement::start_of_paragraph(map, head, 1),
14152                    SelectionGoal::None,
14153                )
14154            });
14155        })
14156    }
14157
14158    pub fn select_to_end_of_paragraph(
14159        &mut self,
14160        _: &SelectToEndOfParagraph,
14161        window: &mut Window,
14162        cx: &mut Context<Self>,
14163    ) {
14164        if matches!(self.mode, EditorMode::SingleLine) {
14165            cx.propagate();
14166            return;
14167        }
14168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14169        self.change_selections(Default::default(), window, cx, |s| {
14170            s.move_heads_with(|map, head, _| {
14171                (
14172                    movement::end_of_paragraph(map, head, 1),
14173                    SelectionGoal::None,
14174                )
14175            });
14176        })
14177    }
14178
14179    pub fn move_to_start_of_excerpt(
14180        &mut self,
14181        _: &MoveToStartOfExcerpt,
14182        window: &mut Window,
14183        cx: &mut Context<Self>,
14184    ) {
14185        if matches!(self.mode, EditorMode::SingleLine) {
14186            cx.propagate();
14187            return;
14188        }
14189        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14190        self.change_selections(Default::default(), window, cx, |s| {
14191            s.move_with(|map, selection| {
14192                selection.collapse_to(
14193                    movement::start_of_excerpt(
14194                        map,
14195                        selection.head(),
14196                        workspace::searchable::Direction::Prev,
14197                    ),
14198                    SelectionGoal::None,
14199                )
14200            });
14201        })
14202    }
14203
14204    pub fn move_to_start_of_next_excerpt(
14205        &mut self,
14206        _: &MoveToStartOfNextExcerpt,
14207        window: &mut Window,
14208        cx: &mut Context<Self>,
14209    ) {
14210        if matches!(self.mode, EditorMode::SingleLine) {
14211            cx.propagate();
14212            return;
14213        }
14214
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::Next,
14222                    ),
14223                    SelectionGoal::None,
14224                )
14225            });
14226        })
14227    }
14228
14229    pub fn move_to_end_of_excerpt(
14230        &mut self,
14231        _: &MoveToEndOfExcerpt,
14232        window: &mut Window,
14233        cx: &mut Context<Self>,
14234    ) {
14235        if matches!(self.mode, EditorMode::SingleLine) {
14236            cx.propagate();
14237            return;
14238        }
14239        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14240        self.change_selections(Default::default(), window, cx, |s| {
14241            s.move_with(|map, selection| {
14242                selection.collapse_to(
14243                    movement::end_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_previous_excerpt(
14255        &mut self,
14256        _: &MoveToEndOfPreviousExcerpt,
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::Prev,
14272                    ),
14273                    SelectionGoal::None,
14274                )
14275            });
14276        })
14277    }
14278
14279    pub fn select_to_start_of_excerpt(
14280        &mut self,
14281        _: &SelectToStartOfExcerpt,
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_heads_with(|map, head, _| {
14292                (
14293                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14294                    SelectionGoal::None,
14295                )
14296            });
14297        })
14298    }
14299
14300    pub fn select_to_start_of_next_excerpt(
14301        &mut self,
14302        _: &SelectToStartOfNextExcerpt,
14303        window: &mut Window,
14304        cx: &mut Context<Self>,
14305    ) {
14306        if matches!(self.mode, EditorMode::SingleLine) {
14307            cx.propagate();
14308            return;
14309        }
14310        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14311        self.change_selections(Default::default(), window, cx, |s| {
14312            s.move_heads_with(|map, head, _| {
14313                (
14314                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14315                    SelectionGoal::None,
14316                )
14317            });
14318        })
14319    }
14320
14321    pub fn select_to_end_of_excerpt(
14322        &mut self,
14323        _: &SelectToEndOfExcerpt,
14324        window: &mut Window,
14325        cx: &mut Context<Self>,
14326    ) {
14327        if matches!(self.mode, EditorMode::SingleLine) {
14328            cx.propagate();
14329            return;
14330        }
14331        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14332        self.change_selections(Default::default(), window, cx, |s| {
14333            s.move_heads_with(|map, head, _| {
14334                (
14335                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14336                    SelectionGoal::None,
14337                )
14338            });
14339        })
14340    }
14341
14342    pub fn select_to_end_of_previous_excerpt(
14343        &mut self,
14344        _: &SelectToEndOfPreviousExcerpt,
14345        window: &mut Window,
14346        cx: &mut Context<Self>,
14347    ) {
14348        if matches!(self.mode, EditorMode::SingleLine) {
14349            cx.propagate();
14350            return;
14351        }
14352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14353        self.change_selections(Default::default(), window, cx, |s| {
14354            s.move_heads_with(|map, head, _| {
14355                (
14356                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14357                    SelectionGoal::None,
14358                )
14359            });
14360        })
14361    }
14362
14363    pub fn move_to_beginning(
14364        &mut self,
14365        _: &MoveToBeginning,
14366        window: &mut Window,
14367        cx: &mut Context<Self>,
14368    ) {
14369        if matches!(self.mode, EditorMode::SingleLine) {
14370            cx.propagate();
14371            return;
14372        }
14373        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14374        self.change_selections(Default::default(), window, cx, |s| {
14375            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14376        });
14377    }
14378
14379    pub fn select_to_beginning(
14380        &mut self,
14381        _: &SelectToBeginning,
14382        window: &mut Window,
14383        cx: &mut Context<Self>,
14384    ) {
14385        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14386        selection.set_head(Point::zero(), SelectionGoal::None);
14387        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14388        self.change_selections(Default::default(), window, cx, |s| {
14389            s.select(vec![selection]);
14390        });
14391    }
14392
14393    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14394        if matches!(self.mode, EditorMode::SingleLine) {
14395            cx.propagate();
14396            return;
14397        }
14398        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14399        let cursor = self.buffer.read(cx).read(cx).len();
14400        self.change_selections(Default::default(), window, cx, |s| {
14401            s.select_ranges(vec![cursor..cursor])
14402        });
14403    }
14404
14405    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14406        self.nav_history = nav_history;
14407    }
14408
14409    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14410        self.nav_history.as_ref()
14411    }
14412
14413    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14414        self.push_to_nav_history(
14415            self.selections.newest_anchor().head(),
14416            None,
14417            false,
14418            true,
14419            cx,
14420        );
14421    }
14422
14423    fn push_to_nav_history(
14424        &mut self,
14425        cursor_anchor: Anchor,
14426        new_position: Option<Point>,
14427        is_deactivate: bool,
14428        always: bool,
14429        cx: &mut Context<Self>,
14430    ) {
14431        if let Some(nav_history) = self.nav_history.as_mut() {
14432            let buffer = self.buffer.read(cx).read(cx);
14433            let cursor_position = cursor_anchor.to_point(&buffer);
14434            let scroll_state = self.scroll_manager.anchor();
14435            let scroll_top_row = scroll_state.top_row(&buffer);
14436            drop(buffer);
14437
14438            if let Some(new_position) = new_position {
14439                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14440                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14441                    return;
14442                }
14443            }
14444
14445            nav_history.push(
14446                Some(NavigationData {
14447                    cursor_anchor,
14448                    cursor_position,
14449                    scroll_anchor: scroll_state,
14450                    scroll_top_row,
14451                }),
14452                cx,
14453            );
14454            cx.emit(EditorEvent::PushedToNavHistory {
14455                anchor: cursor_anchor,
14456                is_deactivate,
14457            })
14458        }
14459    }
14460
14461    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14462        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14463        let buffer = self.buffer.read(cx).snapshot(cx);
14464        let mut selection = self
14465            .selections
14466            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14467        selection.set_head(buffer.len(), SelectionGoal::None);
14468        self.change_selections(Default::default(), window, cx, |s| {
14469            s.select(vec![selection]);
14470        });
14471    }
14472
14473    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14474        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14475        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14476            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14477        });
14478    }
14479
14480    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14481        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14482        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14483        let mut selections = self.selections.all::<Point>(&display_map);
14484        let max_point = display_map.buffer_snapshot().max_point();
14485        for selection in &mut selections {
14486            let rows = selection.spanned_rows(true, &display_map);
14487            selection.start = Point::new(rows.start.0, 0);
14488            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14489            selection.reversed = false;
14490        }
14491        self.change_selections(Default::default(), window, cx, |s| {
14492            s.select(selections);
14493        });
14494    }
14495
14496    pub fn split_selection_into_lines(
14497        &mut self,
14498        action: &SplitSelectionIntoLines,
14499        window: &mut Window,
14500        cx: &mut Context<Self>,
14501    ) {
14502        let selections = self
14503            .selections
14504            .all::<Point>(&self.display_snapshot(cx))
14505            .into_iter()
14506            .map(|selection| selection.start..selection.end)
14507            .collect::<Vec<_>>();
14508        self.unfold_ranges(&selections, true, true, cx);
14509
14510        let mut new_selection_ranges = Vec::new();
14511        {
14512            let buffer = self.buffer.read(cx).read(cx);
14513            for selection in selections {
14514                for row in selection.start.row..selection.end.row {
14515                    let line_start = Point::new(row, 0);
14516                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14517
14518                    if action.keep_selections {
14519                        // Keep the selection range for each line
14520                        let selection_start = if row == selection.start.row {
14521                            selection.start
14522                        } else {
14523                            line_start
14524                        };
14525                        new_selection_ranges.push(selection_start..line_end);
14526                    } else {
14527                        // Collapse to cursor at end of line
14528                        new_selection_ranges.push(line_end..line_end);
14529                    }
14530                }
14531
14532                let is_multiline_selection = selection.start.row != selection.end.row;
14533                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14534                // so this action feels more ergonomic when paired with other selection operations
14535                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14536                if !should_skip_last {
14537                    if action.keep_selections {
14538                        if is_multiline_selection {
14539                            let line_start = Point::new(selection.end.row, 0);
14540                            new_selection_ranges.push(line_start..selection.end);
14541                        } else {
14542                            new_selection_ranges.push(selection.start..selection.end);
14543                        }
14544                    } else {
14545                        new_selection_ranges.push(selection.end..selection.end);
14546                    }
14547                }
14548            }
14549        }
14550        self.change_selections(Default::default(), window, cx, |s| {
14551            s.select_ranges(new_selection_ranges);
14552        });
14553    }
14554
14555    pub fn add_selection_above(
14556        &mut self,
14557        action: &AddSelectionAbove,
14558        window: &mut Window,
14559        cx: &mut Context<Self>,
14560    ) {
14561        self.add_selection(true, action.skip_soft_wrap, window, cx);
14562    }
14563
14564    pub fn add_selection_below(
14565        &mut self,
14566        action: &AddSelectionBelow,
14567        window: &mut Window,
14568        cx: &mut Context<Self>,
14569    ) {
14570        self.add_selection(false, action.skip_soft_wrap, window, cx);
14571    }
14572
14573    fn add_selection(
14574        &mut self,
14575        above: bool,
14576        skip_soft_wrap: bool,
14577        window: &mut Window,
14578        cx: &mut Context<Self>,
14579    ) {
14580        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14581
14582        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14583        let all_selections = self.selections.all::<Point>(&display_map);
14584        let text_layout_details = self.text_layout_details(window);
14585
14586        let (mut columnar_selections, new_selections_to_columnarize) = {
14587            if let Some(state) = self.add_selections_state.as_ref() {
14588                let columnar_selection_ids: HashSet<_> = state
14589                    .groups
14590                    .iter()
14591                    .flat_map(|group| group.stack.iter())
14592                    .copied()
14593                    .collect();
14594
14595                all_selections
14596                    .into_iter()
14597                    .partition(|s| columnar_selection_ids.contains(&s.id))
14598            } else {
14599                (Vec::new(), all_selections)
14600            }
14601        };
14602
14603        let mut state = self
14604            .add_selections_state
14605            .take()
14606            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14607
14608        for selection in new_selections_to_columnarize {
14609            let range = selection.display_range(&display_map).sorted();
14610            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14611            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14612            let positions = start_x.min(end_x)..start_x.max(end_x);
14613            let mut stack = Vec::new();
14614            for row in range.start.row().0..=range.end.row().0 {
14615                if let Some(selection) = self.selections.build_columnar_selection(
14616                    &display_map,
14617                    DisplayRow(row),
14618                    &positions,
14619                    selection.reversed,
14620                    &text_layout_details,
14621                ) {
14622                    stack.push(selection.id);
14623                    columnar_selections.push(selection);
14624                }
14625            }
14626            if !stack.is_empty() {
14627                if above {
14628                    stack.reverse();
14629                }
14630                state.groups.push(AddSelectionsGroup { above, stack });
14631            }
14632        }
14633
14634        let mut final_selections = Vec::new();
14635        let end_row = if above {
14636            DisplayRow(0)
14637        } else {
14638            display_map.max_point().row()
14639        };
14640
14641        let mut last_added_item_per_group = HashMap::default();
14642        for group in state.groups.iter_mut() {
14643            if let Some(last_id) = group.stack.last() {
14644                last_added_item_per_group.insert(*last_id, group);
14645            }
14646        }
14647
14648        for selection in columnar_selections {
14649            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14650                if above == group.above {
14651                    let range = selection.display_range(&display_map).sorted();
14652                    debug_assert_eq!(range.start.row(), range.end.row());
14653                    let mut row = range.start.row();
14654                    let positions =
14655                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14656                            Pixels::from(start)..Pixels::from(end)
14657                        } else {
14658                            let start_x =
14659                                display_map.x_for_display_point(range.start, &text_layout_details);
14660                            let end_x =
14661                                display_map.x_for_display_point(range.end, &text_layout_details);
14662                            start_x.min(end_x)..start_x.max(end_x)
14663                        };
14664
14665                    let mut maybe_new_selection = None;
14666                    let direction = if above { -1 } else { 1 };
14667
14668                    while row != end_row {
14669                        if skip_soft_wrap {
14670                            row = display_map
14671                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14672                                .row();
14673                        } else if above {
14674                            row.0 -= 1;
14675                        } else {
14676                            row.0 += 1;
14677                        }
14678
14679                        if let Some(new_selection) = self.selections.build_columnar_selection(
14680                            &display_map,
14681                            row,
14682                            &positions,
14683                            selection.reversed,
14684                            &text_layout_details,
14685                        ) {
14686                            maybe_new_selection = Some(new_selection);
14687                            break;
14688                        }
14689                    }
14690
14691                    if let Some(new_selection) = maybe_new_selection {
14692                        group.stack.push(new_selection.id);
14693                        if above {
14694                            final_selections.push(new_selection);
14695                            final_selections.push(selection);
14696                        } else {
14697                            final_selections.push(selection);
14698                            final_selections.push(new_selection);
14699                        }
14700                    } else {
14701                        final_selections.push(selection);
14702                    }
14703                } else {
14704                    group.stack.pop();
14705                }
14706            } else {
14707                final_selections.push(selection);
14708            }
14709        }
14710
14711        self.change_selections(Default::default(), window, cx, |s| {
14712            s.select(final_selections);
14713        });
14714
14715        let final_selection_ids: HashSet<_> = self
14716            .selections
14717            .all::<Point>(&display_map)
14718            .iter()
14719            .map(|s| s.id)
14720            .collect();
14721        state.groups.retain_mut(|group| {
14722            // selections might get merged above so we remove invalid items from stacks
14723            group.stack.retain(|id| final_selection_ids.contains(id));
14724
14725            // single selection in stack can be treated as initial state
14726            group.stack.len() > 1
14727        });
14728
14729        if !state.groups.is_empty() {
14730            self.add_selections_state = Some(state);
14731        }
14732    }
14733
14734    fn select_match_ranges(
14735        &mut self,
14736        range: Range<MultiBufferOffset>,
14737        reversed: bool,
14738        replace_newest: bool,
14739        auto_scroll: Option<Autoscroll>,
14740        window: &mut Window,
14741        cx: &mut Context<Editor>,
14742    ) {
14743        self.unfold_ranges(
14744            std::slice::from_ref(&range),
14745            false,
14746            auto_scroll.is_some(),
14747            cx,
14748        );
14749        let effects = if let Some(scroll) = auto_scroll {
14750            SelectionEffects::scroll(scroll)
14751        } else {
14752            SelectionEffects::no_scroll()
14753        };
14754        self.change_selections(effects, window, cx, |s| {
14755            if replace_newest {
14756                s.delete(s.newest_anchor().id);
14757            }
14758            if reversed {
14759                s.insert_range(range.end..range.start);
14760            } else {
14761                s.insert_range(range);
14762            }
14763        });
14764    }
14765
14766    pub fn select_next_match_internal(
14767        &mut self,
14768        display_map: &DisplaySnapshot,
14769        replace_newest: bool,
14770        autoscroll: Option<Autoscroll>,
14771        window: &mut Window,
14772        cx: &mut Context<Self>,
14773    ) -> Result<()> {
14774        let buffer = display_map.buffer_snapshot();
14775        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14776        if let Some(mut select_next_state) = self.select_next_state.take() {
14777            let query = &select_next_state.query;
14778            if !select_next_state.done {
14779                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14780                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14781                let mut next_selected_range = None;
14782
14783                let bytes_after_last_selection =
14784                    buffer.bytes_in_range(last_selection.end..buffer.len());
14785                let bytes_before_first_selection =
14786                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
14787                let query_matches = query
14788                    .stream_find_iter(bytes_after_last_selection)
14789                    .map(|result| (last_selection.end, result))
14790                    .chain(
14791                        query
14792                            .stream_find_iter(bytes_before_first_selection)
14793                            .map(|result| (MultiBufferOffset(0), result)),
14794                    );
14795
14796                for (start_offset, query_match) in query_matches {
14797                    let query_match = query_match.unwrap(); // can only fail due to I/O
14798                    let offset_range =
14799                        start_offset + query_match.start()..start_offset + query_match.end();
14800
14801                    if !select_next_state.wordwise
14802                        || (!buffer.is_inside_word(offset_range.start, None)
14803                            && !buffer.is_inside_word(offset_range.end, None))
14804                    {
14805                        let idx = selections
14806                            .partition_point(|selection| selection.end <= offset_range.start);
14807                        let overlaps = selections
14808                            .get(idx)
14809                            .map_or(false, |selection| selection.start < offset_range.end);
14810
14811                        if !overlaps {
14812                            next_selected_range = Some(offset_range);
14813                            break;
14814                        }
14815                    }
14816                }
14817
14818                if let Some(next_selected_range) = next_selected_range {
14819                    self.select_match_ranges(
14820                        next_selected_range,
14821                        last_selection.reversed,
14822                        replace_newest,
14823                        autoscroll,
14824                        window,
14825                        cx,
14826                    );
14827                } else {
14828                    select_next_state.done = true;
14829                }
14830            }
14831
14832            self.select_next_state = Some(select_next_state);
14833        } else {
14834            let mut only_carets = true;
14835            let mut same_text_selected = true;
14836            let mut selected_text = None;
14837
14838            let mut selections_iter = selections.iter().peekable();
14839            while let Some(selection) = selections_iter.next() {
14840                if selection.start != selection.end {
14841                    only_carets = false;
14842                }
14843
14844                if same_text_selected {
14845                    if selected_text.is_none() {
14846                        selected_text =
14847                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14848                    }
14849
14850                    if let Some(next_selection) = selections_iter.peek() {
14851                        if next_selection.len() == selection.len() {
14852                            let next_selected_text = buffer
14853                                .text_for_range(next_selection.range())
14854                                .collect::<String>();
14855                            if Some(next_selected_text) != selected_text {
14856                                same_text_selected = false;
14857                                selected_text = None;
14858                            }
14859                        } else {
14860                            same_text_selected = false;
14861                            selected_text = None;
14862                        }
14863                    }
14864                }
14865            }
14866
14867            if only_carets {
14868                for selection in &mut selections {
14869                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14870                    selection.start = word_range.start;
14871                    selection.end = word_range.end;
14872                    selection.goal = SelectionGoal::None;
14873                    selection.reversed = false;
14874                    self.select_match_ranges(
14875                        selection.start..selection.end,
14876                        selection.reversed,
14877                        replace_newest,
14878                        autoscroll,
14879                        window,
14880                        cx,
14881                    );
14882                }
14883
14884                if selections.len() == 1 {
14885                    let selection = selections
14886                        .last()
14887                        .expect("ensured that there's only one selection");
14888                    let query = buffer
14889                        .text_for_range(selection.start..selection.end)
14890                        .collect::<String>();
14891                    let is_empty = query.is_empty();
14892                    let select_state = SelectNextState {
14893                        query: self.build_query(&[query], cx)?,
14894                        wordwise: true,
14895                        done: is_empty,
14896                    };
14897                    self.select_next_state = Some(select_state);
14898                } else {
14899                    self.select_next_state = None;
14900                }
14901            } else if let Some(selected_text) = selected_text {
14902                self.select_next_state = Some(SelectNextState {
14903                    query: self.build_query(&[selected_text], cx)?,
14904                    wordwise: false,
14905                    done: false,
14906                });
14907                self.select_next_match_internal(
14908                    display_map,
14909                    replace_newest,
14910                    autoscroll,
14911                    window,
14912                    cx,
14913                )?;
14914            }
14915        }
14916        Ok(())
14917    }
14918
14919    pub fn select_all_matches(
14920        &mut self,
14921        _action: &SelectAllMatches,
14922        window: &mut Window,
14923        cx: &mut Context<Self>,
14924    ) -> Result<()> {
14925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14926
14927        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14928
14929        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14930        let Some(select_next_state) = self.select_next_state.as_mut() else {
14931            return Ok(());
14932        };
14933        if select_next_state.done {
14934            return Ok(());
14935        }
14936
14937        let mut new_selections = Vec::new();
14938
14939        let reversed = self
14940            .selections
14941            .oldest::<MultiBufferOffset>(&display_map)
14942            .reversed;
14943        let buffer = display_map.buffer_snapshot();
14944        let query_matches = select_next_state
14945            .query
14946            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
14947
14948        for query_match in query_matches.into_iter() {
14949            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14950            let offset_range = if reversed {
14951                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
14952            } else {
14953                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
14954            };
14955
14956            if !select_next_state.wordwise
14957                || (!buffer.is_inside_word(offset_range.start, None)
14958                    && !buffer.is_inside_word(offset_range.end, None))
14959            {
14960                new_selections.push(offset_range.start..offset_range.end);
14961            }
14962        }
14963
14964        select_next_state.done = true;
14965
14966        if new_selections.is_empty() {
14967            log::error!("bug: new_selections is empty in select_all_matches");
14968            return Ok(());
14969        }
14970
14971        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14972        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14973            selections.select_ranges(new_selections)
14974        });
14975
14976        Ok(())
14977    }
14978
14979    pub fn select_next(
14980        &mut self,
14981        action: &SelectNext,
14982        window: &mut Window,
14983        cx: &mut Context<Self>,
14984    ) -> Result<()> {
14985        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14986        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14987        self.select_next_match_internal(
14988            &display_map,
14989            action.replace_newest,
14990            Some(Autoscroll::newest()),
14991            window,
14992            cx,
14993        )?;
14994        Ok(())
14995    }
14996
14997    pub fn select_previous(
14998        &mut self,
14999        action: &SelectPrevious,
15000        window: &mut Window,
15001        cx: &mut Context<Self>,
15002    ) -> Result<()> {
15003        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15004        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15005        let buffer = display_map.buffer_snapshot();
15006        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15007        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15008            let query = &select_prev_state.query;
15009            if !select_prev_state.done {
15010                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15011                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15012                let mut next_selected_range = None;
15013                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15014                let bytes_before_last_selection =
15015                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15016                let bytes_after_first_selection =
15017                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15018                let query_matches = query
15019                    .stream_find_iter(bytes_before_last_selection)
15020                    .map(|result| (last_selection.start, result))
15021                    .chain(
15022                        query
15023                            .stream_find_iter(bytes_after_first_selection)
15024                            .map(|result| (buffer.len(), result)),
15025                    );
15026                for (end_offset, query_match) in query_matches {
15027                    let query_match = query_match.unwrap(); // can only fail due to I/O
15028                    let offset_range =
15029                        end_offset - query_match.end()..end_offset - query_match.start();
15030
15031                    if !select_prev_state.wordwise
15032                        || (!buffer.is_inside_word(offset_range.start, None)
15033                            && !buffer.is_inside_word(offset_range.end, None))
15034                    {
15035                        next_selected_range = Some(offset_range);
15036                        break;
15037                    }
15038                }
15039
15040                if let Some(next_selected_range) = next_selected_range {
15041                    self.select_match_ranges(
15042                        next_selected_range,
15043                        last_selection.reversed,
15044                        action.replace_newest,
15045                        Some(Autoscroll::newest()),
15046                        window,
15047                        cx,
15048                    );
15049                } else {
15050                    select_prev_state.done = true;
15051                }
15052            }
15053
15054            self.select_prev_state = Some(select_prev_state);
15055        } else {
15056            let mut only_carets = true;
15057            let mut same_text_selected = true;
15058            let mut selected_text = None;
15059
15060            let mut selections_iter = selections.iter().peekable();
15061            while let Some(selection) = selections_iter.next() {
15062                if selection.start != selection.end {
15063                    only_carets = false;
15064                }
15065
15066                if same_text_selected {
15067                    if selected_text.is_none() {
15068                        selected_text =
15069                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15070                    }
15071
15072                    if let Some(next_selection) = selections_iter.peek() {
15073                        if next_selection.len() == selection.len() {
15074                            let next_selected_text = buffer
15075                                .text_for_range(next_selection.range())
15076                                .collect::<String>();
15077                            if Some(next_selected_text) != selected_text {
15078                                same_text_selected = false;
15079                                selected_text = None;
15080                            }
15081                        } else {
15082                            same_text_selected = false;
15083                            selected_text = None;
15084                        }
15085                    }
15086                }
15087            }
15088
15089            if only_carets {
15090                for selection in &mut selections {
15091                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15092                    selection.start = word_range.start;
15093                    selection.end = word_range.end;
15094                    selection.goal = SelectionGoal::None;
15095                    selection.reversed = false;
15096                    self.select_match_ranges(
15097                        selection.start..selection.end,
15098                        selection.reversed,
15099                        action.replace_newest,
15100                        Some(Autoscroll::newest()),
15101                        window,
15102                        cx,
15103                    );
15104                }
15105                if selections.len() == 1 {
15106                    let selection = selections
15107                        .last()
15108                        .expect("ensured that there's only one selection");
15109                    let query = buffer
15110                        .text_for_range(selection.start..selection.end)
15111                        .collect::<String>();
15112                    let is_empty = query.is_empty();
15113                    let select_state = SelectNextState {
15114                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15115                        wordwise: true,
15116                        done: is_empty,
15117                    };
15118                    self.select_prev_state = Some(select_state);
15119                } else {
15120                    self.select_prev_state = None;
15121                }
15122            } else if let Some(selected_text) = selected_text {
15123                self.select_prev_state = Some(SelectNextState {
15124                    query: self
15125                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15126                    wordwise: false,
15127                    done: false,
15128                });
15129                self.select_previous(action, window, cx)?;
15130            }
15131        }
15132        Ok(())
15133    }
15134
15135    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15136    /// setting the case sensitivity based on the global
15137    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15138    /// editor's settings.
15139    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15140    where
15141        I: IntoIterator<Item = P>,
15142        P: AsRef<[u8]>,
15143    {
15144        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15145            || EditorSettings::get_global(cx).search.case_sensitive,
15146            |value| value,
15147        );
15148
15149        let mut builder = AhoCorasickBuilder::new();
15150        builder.ascii_case_insensitive(!case_sensitive);
15151        builder.build(patterns)
15152    }
15153
15154    pub fn find_next_match(
15155        &mut self,
15156        _: &FindNextMatch,
15157        window: &mut Window,
15158        cx: &mut Context<Self>,
15159    ) -> Result<()> {
15160        let selections = self.selections.disjoint_anchors_arc();
15161        match selections.first() {
15162            Some(first) if selections.len() >= 2 => {
15163                self.change_selections(Default::default(), window, cx, |s| {
15164                    s.select_ranges([first.range()]);
15165                });
15166            }
15167            _ => self.select_next(
15168                &SelectNext {
15169                    replace_newest: true,
15170                },
15171                window,
15172                cx,
15173            )?,
15174        }
15175        Ok(())
15176    }
15177
15178    pub fn find_previous_match(
15179        &mut self,
15180        _: &FindPreviousMatch,
15181        window: &mut Window,
15182        cx: &mut Context<Self>,
15183    ) -> Result<()> {
15184        let selections = self.selections.disjoint_anchors_arc();
15185        match selections.last() {
15186            Some(last) if selections.len() >= 2 => {
15187                self.change_selections(Default::default(), window, cx, |s| {
15188                    s.select_ranges([last.range()]);
15189                });
15190            }
15191            _ => self.select_previous(
15192                &SelectPrevious {
15193                    replace_newest: true,
15194                },
15195                window,
15196                cx,
15197            )?,
15198        }
15199        Ok(())
15200    }
15201
15202    pub fn toggle_comments(
15203        &mut self,
15204        action: &ToggleComments,
15205        window: &mut Window,
15206        cx: &mut Context<Self>,
15207    ) {
15208        if self.read_only(cx) {
15209            return;
15210        }
15211        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15212        let text_layout_details = &self.text_layout_details(window);
15213        self.transact(window, cx, |this, window, cx| {
15214            let mut selections = this
15215                .selections
15216                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15217            let mut edits = Vec::new();
15218            let mut selection_edit_ranges = Vec::new();
15219            let mut last_toggled_row = None;
15220            let snapshot = this.buffer.read(cx).read(cx);
15221            let empty_str: Arc<str> = Arc::default();
15222            let mut suffixes_inserted = Vec::new();
15223            let ignore_indent = action.ignore_indent;
15224
15225            fn comment_prefix_range(
15226                snapshot: &MultiBufferSnapshot,
15227                row: MultiBufferRow,
15228                comment_prefix: &str,
15229                comment_prefix_whitespace: &str,
15230                ignore_indent: bool,
15231            ) -> Range<Point> {
15232                let indent_size = if ignore_indent {
15233                    0
15234                } else {
15235                    snapshot.indent_size_for_line(row).len
15236                };
15237
15238                let start = Point::new(row.0, indent_size);
15239
15240                let mut line_bytes = snapshot
15241                    .bytes_in_range(start..snapshot.max_point())
15242                    .flatten()
15243                    .copied();
15244
15245                // If this line currently begins with the line comment prefix, then record
15246                // the range containing the prefix.
15247                if line_bytes
15248                    .by_ref()
15249                    .take(comment_prefix.len())
15250                    .eq(comment_prefix.bytes())
15251                {
15252                    // Include any whitespace that matches the comment prefix.
15253                    let matching_whitespace_len = line_bytes
15254                        .zip(comment_prefix_whitespace.bytes())
15255                        .take_while(|(a, b)| a == b)
15256                        .count() as u32;
15257                    let end = Point::new(
15258                        start.row,
15259                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15260                    );
15261                    start..end
15262                } else {
15263                    start..start
15264                }
15265            }
15266
15267            fn comment_suffix_range(
15268                snapshot: &MultiBufferSnapshot,
15269                row: MultiBufferRow,
15270                comment_suffix: &str,
15271                comment_suffix_has_leading_space: bool,
15272            ) -> Range<Point> {
15273                let end = Point::new(row.0, snapshot.line_len(row));
15274                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15275
15276                let mut line_end_bytes = snapshot
15277                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15278                    .flatten()
15279                    .copied();
15280
15281                let leading_space_len = if suffix_start_column > 0
15282                    && line_end_bytes.next() == Some(b' ')
15283                    && comment_suffix_has_leading_space
15284                {
15285                    1
15286                } else {
15287                    0
15288                };
15289
15290                // If this line currently begins with the line comment prefix, then record
15291                // the range containing the prefix.
15292                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15293                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15294                    start..end
15295                } else {
15296                    end..end
15297                }
15298            }
15299
15300            // TODO: Handle selections that cross excerpts
15301            for selection in &mut selections {
15302                let start_column = snapshot
15303                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15304                    .len;
15305                let language = if let Some(language) =
15306                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15307                {
15308                    language
15309                } else {
15310                    continue;
15311                };
15312
15313                selection_edit_ranges.clear();
15314
15315                // If multiple selections contain a given row, avoid processing that
15316                // row more than once.
15317                let mut start_row = MultiBufferRow(selection.start.row);
15318                if last_toggled_row == Some(start_row) {
15319                    start_row = start_row.next_row();
15320                }
15321                let end_row =
15322                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15323                        MultiBufferRow(selection.end.row - 1)
15324                    } else {
15325                        MultiBufferRow(selection.end.row)
15326                    };
15327                last_toggled_row = Some(end_row);
15328
15329                if start_row > end_row {
15330                    continue;
15331                }
15332
15333                // If the language has line comments, toggle those.
15334                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15335
15336                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15337                if ignore_indent {
15338                    full_comment_prefixes = full_comment_prefixes
15339                        .into_iter()
15340                        .map(|s| Arc::from(s.trim_end()))
15341                        .collect();
15342                }
15343
15344                if !full_comment_prefixes.is_empty() {
15345                    let first_prefix = full_comment_prefixes
15346                        .first()
15347                        .expect("prefixes is non-empty");
15348                    let prefix_trimmed_lengths = full_comment_prefixes
15349                        .iter()
15350                        .map(|p| p.trim_end_matches(' ').len())
15351                        .collect::<SmallVec<[usize; 4]>>();
15352
15353                    let mut all_selection_lines_are_comments = true;
15354
15355                    for row in start_row.0..=end_row.0 {
15356                        let row = MultiBufferRow(row);
15357                        if start_row < end_row && snapshot.is_line_blank(row) {
15358                            continue;
15359                        }
15360
15361                        let prefix_range = full_comment_prefixes
15362                            .iter()
15363                            .zip(prefix_trimmed_lengths.iter().copied())
15364                            .map(|(prefix, trimmed_prefix_len)| {
15365                                comment_prefix_range(
15366                                    snapshot.deref(),
15367                                    row,
15368                                    &prefix[..trimmed_prefix_len],
15369                                    &prefix[trimmed_prefix_len..],
15370                                    ignore_indent,
15371                                )
15372                            })
15373                            .max_by_key(|range| range.end.column - range.start.column)
15374                            .expect("prefixes is non-empty");
15375
15376                        if prefix_range.is_empty() {
15377                            all_selection_lines_are_comments = false;
15378                        }
15379
15380                        selection_edit_ranges.push(prefix_range);
15381                    }
15382
15383                    if all_selection_lines_are_comments {
15384                        edits.extend(
15385                            selection_edit_ranges
15386                                .iter()
15387                                .cloned()
15388                                .map(|range| (range, empty_str.clone())),
15389                        );
15390                    } else {
15391                        let min_column = selection_edit_ranges
15392                            .iter()
15393                            .map(|range| range.start.column)
15394                            .min()
15395                            .unwrap_or(0);
15396                        edits.extend(selection_edit_ranges.iter().map(|range| {
15397                            let position = Point::new(range.start.row, min_column);
15398                            (position..position, first_prefix.clone())
15399                        }));
15400                    }
15401                } else if let Some(BlockCommentConfig {
15402                    start: full_comment_prefix,
15403                    end: comment_suffix,
15404                    ..
15405                }) = language.block_comment()
15406                {
15407                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15408                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15409                    let prefix_range = comment_prefix_range(
15410                        snapshot.deref(),
15411                        start_row,
15412                        comment_prefix,
15413                        comment_prefix_whitespace,
15414                        ignore_indent,
15415                    );
15416                    let suffix_range = comment_suffix_range(
15417                        snapshot.deref(),
15418                        end_row,
15419                        comment_suffix.trim_start_matches(' '),
15420                        comment_suffix.starts_with(' '),
15421                    );
15422
15423                    if prefix_range.is_empty() || suffix_range.is_empty() {
15424                        edits.push((
15425                            prefix_range.start..prefix_range.start,
15426                            full_comment_prefix.clone(),
15427                        ));
15428                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15429                        suffixes_inserted.push((end_row, comment_suffix.len()));
15430                    } else {
15431                        edits.push((prefix_range, empty_str.clone()));
15432                        edits.push((suffix_range, empty_str.clone()));
15433                    }
15434                } else {
15435                    continue;
15436                }
15437            }
15438
15439            drop(snapshot);
15440            this.buffer.update(cx, |buffer, cx| {
15441                buffer.edit(edits, None, cx);
15442            });
15443
15444            // Adjust selections so that they end before any comment suffixes that
15445            // were inserted.
15446            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15447            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15448            let snapshot = this.buffer.read(cx).read(cx);
15449            for selection in &mut selections {
15450                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15451                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15452                        Ordering::Less => {
15453                            suffixes_inserted.next();
15454                            continue;
15455                        }
15456                        Ordering::Greater => break,
15457                        Ordering::Equal => {
15458                            if selection.end.column == snapshot.line_len(row) {
15459                                if selection.is_empty() {
15460                                    selection.start.column -= suffix_len as u32;
15461                                }
15462                                selection.end.column -= suffix_len as u32;
15463                            }
15464                            break;
15465                        }
15466                    }
15467                }
15468            }
15469
15470            drop(snapshot);
15471            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15472
15473            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15474            let selections_on_single_row = selections.windows(2).all(|selections| {
15475                selections[0].start.row == selections[1].start.row
15476                    && selections[0].end.row == selections[1].end.row
15477                    && selections[0].start.row == selections[0].end.row
15478            });
15479            let selections_selecting = selections
15480                .iter()
15481                .any(|selection| selection.start != selection.end);
15482            let advance_downwards = action.advance_downwards
15483                && selections_on_single_row
15484                && !selections_selecting
15485                && !matches!(this.mode, EditorMode::SingleLine);
15486
15487            if advance_downwards {
15488                let snapshot = this.buffer.read(cx).snapshot(cx);
15489
15490                this.change_selections(Default::default(), window, cx, |s| {
15491                    s.move_cursors_with(|display_snapshot, display_point, _| {
15492                        let mut point = display_point.to_point(display_snapshot);
15493                        point.row += 1;
15494                        point = snapshot.clip_point(point, Bias::Left);
15495                        let display_point = point.to_display_point(display_snapshot);
15496                        let goal = SelectionGoal::HorizontalPosition(
15497                            display_snapshot
15498                                .x_for_display_point(display_point, text_layout_details)
15499                                .into(),
15500                        );
15501                        (display_point, goal)
15502                    })
15503                });
15504            }
15505        });
15506    }
15507
15508    pub fn select_enclosing_symbol(
15509        &mut self,
15510        _: &SelectEnclosingSymbol,
15511        window: &mut Window,
15512        cx: &mut Context<Self>,
15513    ) {
15514        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15515
15516        let buffer = self.buffer.read(cx).snapshot(cx);
15517        let old_selections = self
15518            .selections
15519            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15520            .into_boxed_slice();
15521
15522        fn update_selection(
15523            selection: &Selection<MultiBufferOffset>,
15524            buffer_snap: &MultiBufferSnapshot,
15525        ) -> Option<Selection<MultiBufferOffset>> {
15526            let cursor = selection.head();
15527            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15528            for symbol in symbols.iter().rev() {
15529                let start = symbol.range.start.to_offset(buffer_snap);
15530                let end = symbol.range.end.to_offset(buffer_snap);
15531                let new_range = start..end;
15532                if start < selection.start || end > selection.end {
15533                    return Some(Selection {
15534                        id: selection.id,
15535                        start: new_range.start,
15536                        end: new_range.end,
15537                        goal: SelectionGoal::None,
15538                        reversed: selection.reversed,
15539                    });
15540                }
15541            }
15542            None
15543        }
15544
15545        let mut selected_larger_symbol = false;
15546        let new_selections = old_selections
15547            .iter()
15548            .map(|selection| match update_selection(selection, &buffer) {
15549                Some(new_selection) => {
15550                    if new_selection.range() != selection.range() {
15551                        selected_larger_symbol = true;
15552                    }
15553                    new_selection
15554                }
15555                None => selection.clone(),
15556            })
15557            .collect::<Vec<_>>();
15558
15559        if selected_larger_symbol {
15560            self.change_selections(Default::default(), window, cx, |s| {
15561                s.select(new_selections);
15562            });
15563        }
15564    }
15565
15566    pub fn select_larger_syntax_node(
15567        &mut self,
15568        _: &SelectLargerSyntaxNode,
15569        window: &mut Window,
15570        cx: &mut Context<Self>,
15571    ) {
15572        let Some(visible_row_count) = self.visible_row_count() else {
15573            return;
15574        };
15575        let old_selections: Box<[_]> = self
15576            .selections
15577            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15578            .into();
15579        if old_selections.is_empty() {
15580            return;
15581        }
15582
15583        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15584
15585        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15586        let buffer = self.buffer.read(cx).snapshot(cx);
15587
15588        let mut selected_larger_node = false;
15589        let mut new_selections = old_selections
15590            .iter()
15591            .map(|selection| {
15592                let old_range = selection.start..selection.end;
15593
15594                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15595                    // manually select word at selection
15596                    if ["string_content", "inline"].contains(&node.kind()) {
15597                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15598                        // ignore if word is already selected
15599                        if !word_range.is_empty() && old_range != word_range {
15600                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15601                            // only select word if start and end point belongs to same word
15602                            if word_range == last_word_range {
15603                                selected_larger_node = true;
15604                                return Selection {
15605                                    id: selection.id,
15606                                    start: word_range.start,
15607                                    end: word_range.end,
15608                                    goal: SelectionGoal::None,
15609                                    reversed: selection.reversed,
15610                                };
15611                            }
15612                        }
15613                    }
15614                }
15615
15616                let mut new_range = old_range.clone();
15617                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15618                    new_range = range;
15619                    if !node.is_named() {
15620                        continue;
15621                    }
15622                    if !display_map.intersects_fold(new_range.start)
15623                        && !display_map.intersects_fold(new_range.end)
15624                    {
15625                        break;
15626                    }
15627                }
15628
15629                selected_larger_node |= new_range != old_range;
15630                Selection {
15631                    id: selection.id,
15632                    start: new_range.start,
15633                    end: new_range.end,
15634                    goal: SelectionGoal::None,
15635                    reversed: selection.reversed,
15636                }
15637            })
15638            .collect::<Vec<_>>();
15639
15640        if !selected_larger_node {
15641            return; // don't put this call in the history
15642        }
15643
15644        // scroll based on transformation done to the last selection created by the user
15645        let (last_old, last_new) = old_selections
15646            .last()
15647            .zip(new_selections.last().cloned())
15648            .expect("old_selections isn't empty");
15649
15650        // revert selection
15651        let is_selection_reversed = {
15652            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15653            new_selections.last_mut().expect("checked above").reversed =
15654                should_newest_selection_be_reversed;
15655            should_newest_selection_be_reversed
15656        };
15657
15658        if selected_larger_node {
15659            self.select_syntax_node_history.disable_clearing = true;
15660            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15661                s.select(new_selections.clone());
15662            });
15663            self.select_syntax_node_history.disable_clearing = false;
15664        }
15665
15666        let start_row = last_new.start.to_display_point(&display_map).row().0;
15667        let end_row = last_new.end.to_display_point(&display_map).row().0;
15668        let selection_height = end_row - start_row + 1;
15669        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15670
15671        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15672        let scroll_behavior = if fits_on_the_screen {
15673            self.request_autoscroll(Autoscroll::fit(), cx);
15674            SelectSyntaxNodeScrollBehavior::FitSelection
15675        } else if is_selection_reversed {
15676            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15677            SelectSyntaxNodeScrollBehavior::CursorTop
15678        } else {
15679            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15680            SelectSyntaxNodeScrollBehavior::CursorBottom
15681        };
15682
15683        self.select_syntax_node_history.push((
15684            old_selections,
15685            scroll_behavior,
15686            is_selection_reversed,
15687        ));
15688    }
15689
15690    pub fn select_smaller_syntax_node(
15691        &mut self,
15692        _: &SelectSmallerSyntaxNode,
15693        window: &mut Window,
15694        cx: &mut Context<Self>,
15695    ) {
15696        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15697
15698        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15699            self.select_syntax_node_history.pop()
15700        {
15701            if let Some(selection) = selections.last_mut() {
15702                selection.reversed = is_selection_reversed;
15703            }
15704
15705            self.select_syntax_node_history.disable_clearing = true;
15706            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15707                s.select(selections.to_vec());
15708            });
15709            self.select_syntax_node_history.disable_clearing = false;
15710
15711            match scroll_behavior {
15712                SelectSyntaxNodeScrollBehavior::CursorTop => {
15713                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15714                }
15715                SelectSyntaxNodeScrollBehavior::FitSelection => {
15716                    self.request_autoscroll(Autoscroll::fit(), cx);
15717                }
15718                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15719                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15720                }
15721            }
15722        }
15723    }
15724
15725    pub fn unwrap_syntax_node(
15726        &mut self,
15727        _: &UnwrapSyntaxNode,
15728        window: &mut Window,
15729        cx: &mut Context<Self>,
15730    ) {
15731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15732
15733        let buffer = self.buffer.read(cx).snapshot(cx);
15734        let selections = self
15735            .selections
15736            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15737            .into_iter()
15738            // subtracting the offset requires sorting
15739            .sorted_by_key(|i| i.start);
15740
15741        let full_edits = selections
15742            .into_iter()
15743            .filter_map(|selection| {
15744                let child = if selection.is_empty()
15745                    && let Some((_, ancestor_range)) =
15746                        buffer.syntax_ancestor(selection.start..selection.end)
15747                {
15748                    ancestor_range
15749                } else {
15750                    selection.range()
15751                };
15752
15753                let mut parent = child.clone();
15754                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15755                    parent = ancestor_range;
15756                    if parent.start < child.start || parent.end > child.end {
15757                        break;
15758                    }
15759                }
15760
15761                if parent == child {
15762                    return None;
15763                }
15764                let text = buffer.text_for_range(child).collect::<String>();
15765                Some((selection.id, parent, text))
15766            })
15767            .collect::<Vec<_>>();
15768        if full_edits.is_empty() {
15769            return;
15770        }
15771
15772        self.transact(window, cx, |this, window, cx| {
15773            this.buffer.update(cx, |buffer, cx| {
15774                buffer.edit(
15775                    full_edits
15776                        .iter()
15777                        .map(|(_, p, t)| (p.clone(), t.clone()))
15778                        .collect::<Vec<_>>(),
15779                    None,
15780                    cx,
15781                );
15782            });
15783            this.change_selections(Default::default(), window, cx, |s| {
15784                let mut offset = 0;
15785                let mut selections = vec![];
15786                for (id, parent, text) in full_edits {
15787                    let start = parent.start - offset;
15788                    offset += (parent.end - parent.start) - text.len();
15789                    selections.push(Selection {
15790                        id,
15791                        start,
15792                        end: start + text.len(),
15793                        reversed: false,
15794                        goal: Default::default(),
15795                    });
15796                }
15797                s.select(selections);
15798            });
15799        });
15800    }
15801
15802    pub fn select_next_syntax_node(
15803        &mut self,
15804        _: &SelectNextSyntaxNode,
15805        window: &mut Window,
15806        cx: &mut Context<Self>,
15807    ) {
15808        let old_selections: Box<[_]> = self
15809            .selections
15810            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15811            .into();
15812        if old_selections.is_empty() {
15813            return;
15814        }
15815
15816        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15817
15818        let buffer = self.buffer.read(cx).snapshot(cx);
15819        let mut selected_sibling = false;
15820
15821        let new_selections = old_selections
15822            .iter()
15823            .map(|selection| {
15824                let old_range = selection.start..selection.end;
15825
15826                let old_range =
15827                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15828                let excerpt = buffer.excerpt_containing(old_range.clone());
15829
15830                if let Some(mut excerpt) = excerpt
15831                    && let Some(node) = excerpt
15832                        .buffer()
15833                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
15834                {
15835                    let new_range = excerpt.map_range_from_buffer(
15836                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15837                    );
15838                    selected_sibling = true;
15839                    Selection {
15840                        id: selection.id,
15841                        start: new_range.start,
15842                        end: new_range.end,
15843                        goal: SelectionGoal::None,
15844                        reversed: selection.reversed,
15845                    }
15846                } else {
15847                    selection.clone()
15848                }
15849            })
15850            .collect::<Vec<_>>();
15851
15852        if selected_sibling {
15853            self.change_selections(
15854                SelectionEffects::scroll(Autoscroll::fit()),
15855                window,
15856                cx,
15857                |s| {
15858                    s.select(new_selections);
15859                },
15860            );
15861        }
15862    }
15863
15864    pub fn select_prev_syntax_node(
15865        &mut self,
15866        _: &SelectPreviousSyntaxNode,
15867        window: &mut Window,
15868        cx: &mut Context<Self>,
15869    ) {
15870        let old_selections: Box<[_]> = self
15871            .selections
15872            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15873            .into();
15874        if old_selections.is_empty() {
15875            return;
15876        }
15877
15878        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15879
15880        let buffer = self.buffer.read(cx).snapshot(cx);
15881        let mut selected_sibling = false;
15882
15883        let new_selections = old_selections
15884            .iter()
15885            .map(|selection| {
15886                let old_range = selection.start..selection.end;
15887                let old_range =
15888                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15889                let excerpt = buffer.excerpt_containing(old_range.clone());
15890
15891                if let Some(mut excerpt) = excerpt
15892                    && let Some(node) = excerpt
15893                        .buffer()
15894                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
15895                {
15896                    let new_range = excerpt.map_range_from_buffer(
15897                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15898                    );
15899                    selected_sibling = true;
15900                    Selection {
15901                        id: selection.id,
15902                        start: new_range.start,
15903                        end: new_range.end,
15904                        goal: SelectionGoal::None,
15905                        reversed: selection.reversed,
15906                    }
15907                } else {
15908                    selection.clone()
15909                }
15910            })
15911            .collect::<Vec<_>>();
15912
15913        if selected_sibling {
15914            self.change_selections(
15915                SelectionEffects::scroll(Autoscroll::fit()),
15916                window,
15917                cx,
15918                |s| {
15919                    s.select(new_selections);
15920                },
15921            );
15922        }
15923    }
15924
15925    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15926        if !EditorSettings::get_global(cx).gutter.runnables {
15927            self.clear_tasks();
15928            return Task::ready(());
15929        }
15930        let project = self.project().map(Entity::downgrade);
15931        let task_sources = self.lsp_task_sources(cx);
15932        let multi_buffer = self.buffer.downgrade();
15933        cx.spawn_in(window, async move |editor, cx| {
15934            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15935            let Some(project) = project.and_then(|p| p.upgrade()) else {
15936                return;
15937            };
15938            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15939                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15940            }) else {
15941                return;
15942            };
15943
15944            let hide_runnables = project
15945                .update(cx, |project, _| project.is_via_collab())
15946                .unwrap_or(true);
15947            if hide_runnables {
15948                return;
15949            }
15950            let new_rows =
15951                cx.background_spawn({
15952                    let snapshot = display_snapshot.clone();
15953                    async move {
15954                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15955                    }
15956                })
15957                    .await;
15958            let Ok(lsp_tasks) =
15959                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15960            else {
15961                return;
15962            };
15963            let lsp_tasks = lsp_tasks.await;
15964
15965            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15966                lsp_tasks
15967                    .into_iter()
15968                    .flat_map(|(kind, tasks)| {
15969                        tasks.into_iter().filter_map(move |(location, task)| {
15970                            Some((kind.clone(), location?, task))
15971                        })
15972                    })
15973                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15974                        let buffer = location.target.buffer;
15975                        let buffer_snapshot = buffer.read(cx).snapshot();
15976                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15977                            |(excerpt_id, snapshot, _)| {
15978                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15979                                    display_snapshot
15980                                        .buffer_snapshot()
15981                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15982                                } else {
15983                                    None
15984                                }
15985                            },
15986                        );
15987                        if let Some(offset) = offset {
15988                            let task_buffer_range =
15989                                location.target.range.to_point(&buffer_snapshot);
15990                            let context_buffer_range =
15991                                task_buffer_range.to_offset(&buffer_snapshot);
15992                            let context_range = BufferOffset(context_buffer_range.start)
15993                                ..BufferOffset(context_buffer_range.end);
15994
15995                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15996                                .or_insert_with(|| RunnableTasks {
15997                                    templates: Vec::new(),
15998                                    offset,
15999                                    column: task_buffer_range.start.column,
16000                                    extra_variables: HashMap::default(),
16001                                    context_range,
16002                                })
16003                                .templates
16004                                .push((kind, task.original_task().clone()));
16005                        }
16006
16007                        acc
16008                    })
16009            }) else {
16010                return;
16011            };
16012
16013            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16014                buffer.language_settings(cx).tasks.prefer_lsp
16015            }) else {
16016                return;
16017            };
16018
16019            let rows = Self::runnable_rows(
16020                project,
16021                display_snapshot,
16022                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16023                new_rows,
16024                cx.clone(),
16025            )
16026            .await;
16027            editor
16028                .update(cx, |editor, _| {
16029                    editor.clear_tasks();
16030                    for (key, mut value) in rows {
16031                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16032                            value.templates.extend(lsp_tasks.templates);
16033                        }
16034
16035                        editor.insert_tasks(key, value);
16036                    }
16037                    for (key, value) in lsp_tasks_by_rows {
16038                        editor.insert_tasks(key, value);
16039                    }
16040                })
16041                .ok();
16042        })
16043    }
16044    fn fetch_runnable_ranges(
16045        snapshot: &DisplaySnapshot,
16046        range: Range<Anchor>,
16047    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16048        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16049    }
16050
16051    fn runnable_rows(
16052        project: Entity<Project>,
16053        snapshot: DisplaySnapshot,
16054        prefer_lsp: bool,
16055        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16056        cx: AsyncWindowContext,
16057    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16058        cx.spawn(async move |cx| {
16059            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16060            for (run_range, mut runnable) in runnable_ranges {
16061                let Some(tasks) = cx
16062                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16063                    .ok()
16064                else {
16065                    continue;
16066                };
16067                let mut tasks = tasks.await;
16068
16069                if prefer_lsp {
16070                    tasks.retain(|(task_kind, _)| {
16071                        !matches!(task_kind, TaskSourceKind::Language { .. })
16072                    });
16073                }
16074                if tasks.is_empty() {
16075                    continue;
16076                }
16077
16078                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16079                let Some(row) = snapshot
16080                    .buffer_snapshot()
16081                    .buffer_line_for_row(MultiBufferRow(point.row))
16082                    .map(|(_, range)| range.start.row)
16083                else {
16084                    continue;
16085                };
16086
16087                let context_range =
16088                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16089                runnable_rows.push((
16090                    (runnable.buffer_id, row),
16091                    RunnableTasks {
16092                        templates: tasks,
16093                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16094                        context_range,
16095                        column: point.column,
16096                        extra_variables: runnable.extra_captures,
16097                    },
16098                ));
16099            }
16100            runnable_rows
16101        })
16102    }
16103
16104    fn templates_with_tags(
16105        project: &Entity<Project>,
16106        runnable: &mut Runnable,
16107        cx: &mut App,
16108    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16109        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16110            let (worktree_id, file) = project
16111                .buffer_for_id(runnable.buffer, cx)
16112                .and_then(|buffer| buffer.read(cx).file())
16113                .map(|file| (file.worktree_id(cx), file.clone()))
16114                .unzip();
16115
16116            (
16117                project.task_store().read(cx).task_inventory().cloned(),
16118                worktree_id,
16119                file,
16120            )
16121        });
16122
16123        let tags = mem::take(&mut runnable.tags);
16124        let language = runnable.language.clone();
16125        cx.spawn(async move |cx| {
16126            let mut templates_with_tags = Vec::new();
16127            if let Some(inventory) = inventory {
16128                for RunnableTag(tag) in tags {
16129                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16130                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16131                    }) else {
16132                        return templates_with_tags;
16133                    };
16134                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16135                        move |(_, template)| {
16136                            template.tags.iter().any(|source_tag| source_tag == &tag)
16137                        },
16138                    ));
16139                }
16140            }
16141            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16142
16143            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16144                // Strongest source wins; if we have worktree tag binding, prefer that to
16145                // global and language bindings;
16146                // if we have a global binding, prefer that to language binding.
16147                let first_mismatch = templates_with_tags
16148                    .iter()
16149                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16150                if let Some(index) = first_mismatch {
16151                    templates_with_tags.truncate(index);
16152                }
16153            }
16154
16155            templates_with_tags
16156        })
16157    }
16158
16159    pub fn move_to_enclosing_bracket(
16160        &mut self,
16161        _: &MoveToEnclosingBracket,
16162        window: &mut Window,
16163        cx: &mut Context<Self>,
16164    ) {
16165        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16166        self.change_selections(Default::default(), window, cx, |s| {
16167            s.move_offsets_with(|snapshot, selection| {
16168                let Some(enclosing_bracket_ranges) =
16169                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16170                else {
16171                    return;
16172                };
16173
16174                let mut best_length = usize::MAX;
16175                let mut best_inside = false;
16176                let mut best_in_bracket_range = false;
16177                let mut best_destination = None;
16178                for (open, close) in enclosing_bracket_ranges {
16179                    let close = close.to_inclusive();
16180                    let length = *close.end() - open.start;
16181                    let inside = selection.start >= open.end && selection.end <= *close.start();
16182                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16183                        || close.contains(&selection.head());
16184
16185                    // If best is next to a bracket and current isn't, skip
16186                    if !in_bracket_range && best_in_bracket_range {
16187                        continue;
16188                    }
16189
16190                    // Prefer smaller lengths unless best is inside and current isn't
16191                    if length > best_length && (best_inside || !inside) {
16192                        continue;
16193                    }
16194
16195                    best_length = length;
16196                    best_inside = inside;
16197                    best_in_bracket_range = in_bracket_range;
16198                    best_destination = Some(
16199                        if close.contains(&selection.start) && close.contains(&selection.end) {
16200                            if inside { open.end } else { open.start }
16201                        } else if inside {
16202                            *close.start()
16203                        } else {
16204                            *close.end()
16205                        },
16206                    );
16207                }
16208
16209                if let Some(destination) = best_destination {
16210                    selection.collapse_to(destination, SelectionGoal::None);
16211                }
16212            })
16213        });
16214    }
16215
16216    pub fn undo_selection(
16217        &mut self,
16218        _: &UndoSelection,
16219        window: &mut Window,
16220        cx: &mut Context<Self>,
16221    ) {
16222        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16223        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16224            self.selection_history.mode = SelectionHistoryMode::Undoing;
16225            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16226                this.end_selection(window, cx);
16227                this.change_selections(
16228                    SelectionEffects::scroll(Autoscroll::newest()),
16229                    window,
16230                    cx,
16231                    |s| s.select_anchors(entry.selections.to_vec()),
16232                );
16233            });
16234            self.selection_history.mode = SelectionHistoryMode::Normal;
16235
16236            self.select_next_state = entry.select_next_state;
16237            self.select_prev_state = entry.select_prev_state;
16238            self.add_selections_state = entry.add_selections_state;
16239        }
16240    }
16241
16242    pub fn redo_selection(
16243        &mut self,
16244        _: &RedoSelection,
16245        window: &mut Window,
16246        cx: &mut Context<Self>,
16247    ) {
16248        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16249        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16250            self.selection_history.mode = SelectionHistoryMode::Redoing;
16251            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16252                this.end_selection(window, cx);
16253                this.change_selections(
16254                    SelectionEffects::scroll(Autoscroll::newest()),
16255                    window,
16256                    cx,
16257                    |s| s.select_anchors(entry.selections.to_vec()),
16258                );
16259            });
16260            self.selection_history.mode = SelectionHistoryMode::Normal;
16261
16262            self.select_next_state = entry.select_next_state;
16263            self.select_prev_state = entry.select_prev_state;
16264            self.add_selections_state = entry.add_selections_state;
16265        }
16266    }
16267
16268    pub fn expand_excerpts(
16269        &mut self,
16270        action: &ExpandExcerpts,
16271        _: &mut Window,
16272        cx: &mut Context<Self>,
16273    ) {
16274        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16275    }
16276
16277    pub fn expand_excerpts_down(
16278        &mut self,
16279        action: &ExpandExcerptsDown,
16280        _: &mut Window,
16281        cx: &mut Context<Self>,
16282    ) {
16283        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16284    }
16285
16286    pub fn expand_excerpts_up(
16287        &mut self,
16288        action: &ExpandExcerptsUp,
16289        _: &mut Window,
16290        cx: &mut Context<Self>,
16291    ) {
16292        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16293    }
16294
16295    pub fn expand_excerpts_for_direction(
16296        &mut self,
16297        lines: u32,
16298        direction: ExpandExcerptDirection,
16299
16300        cx: &mut Context<Self>,
16301    ) {
16302        let selections = self.selections.disjoint_anchors_arc();
16303
16304        let lines = if lines == 0 {
16305            EditorSettings::get_global(cx).expand_excerpt_lines
16306        } else {
16307            lines
16308        };
16309
16310        self.buffer.update(cx, |buffer, cx| {
16311            let snapshot = buffer.snapshot(cx);
16312            let mut excerpt_ids = selections
16313                .iter()
16314                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16315                .collect::<Vec<_>>();
16316            excerpt_ids.sort();
16317            excerpt_ids.dedup();
16318            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16319        })
16320    }
16321
16322    pub fn expand_excerpt(
16323        &mut self,
16324        excerpt: ExcerptId,
16325        direction: ExpandExcerptDirection,
16326        window: &mut Window,
16327        cx: &mut Context<Self>,
16328    ) {
16329        let current_scroll_position = self.scroll_position(cx);
16330        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16331        let mut scroll = None;
16332
16333        if direction == ExpandExcerptDirection::Down {
16334            let multi_buffer = self.buffer.read(cx);
16335            let snapshot = multi_buffer.snapshot(cx);
16336            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16337                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16338                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16339            {
16340                let buffer_snapshot = buffer.read(cx).snapshot();
16341                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16342                let last_row = buffer_snapshot.max_point().row;
16343                let lines_below = last_row.saturating_sub(excerpt_end_row);
16344                if lines_below >= lines_to_expand {
16345                    scroll = Some(
16346                        current_scroll_position
16347                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16348                    );
16349                }
16350            }
16351        }
16352        if direction == ExpandExcerptDirection::Up
16353            && self
16354                .buffer
16355                .read(cx)
16356                .snapshot(cx)
16357                .excerpt_before(excerpt)
16358                .is_none()
16359        {
16360            scroll = Some(current_scroll_position);
16361        }
16362
16363        self.buffer.update(cx, |buffer, cx| {
16364            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16365        });
16366
16367        if let Some(new_scroll_position) = scroll {
16368            self.set_scroll_position(new_scroll_position, window, cx);
16369        }
16370    }
16371
16372    pub fn go_to_singleton_buffer_point(
16373        &mut self,
16374        point: Point,
16375        window: &mut Window,
16376        cx: &mut Context<Self>,
16377    ) {
16378        self.go_to_singleton_buffer_range(point..point, window, cx);
16379    }
16380
16381    pub fn go_to_singleton_buffer_range(
16382        &mut self,
16383        range: Range<Point>,
16384        window: &mut Window,
16385        cx: &mut Context<Self>,
16386    ) {
16387        let multibuffer = self.buffer().read(cx);
16388        let Some(buffer) = multibuffer.as_singleton() else {
16389            return;
16390        };
16391        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16392            return;
16393        };
16394        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16395            return;
16396        };
16397        self.change_selections(
16398            SelectionEffects::default().nav_history(true),
16399            window,
16400            cx,
16401            |s| s.select_anchor_ranges([start..end]),
16402        );
16403    }
16404
16405    pub fn go_to_diagnostic(
16406        &mut self,
16407        action: &GoToDiagnostic,
16408        window: &mut Window,
16409        cx: &mut Context<Self>,
16410    ) {
16411        if !self.diagnostics_enabled() {
16412            return;
16413        }
16414        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16415        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16416    }
16417
16418    pub fn go_to_prev_diagnostic(
16419        &mut self,
16420        action: &GoToPreviousDiagnostic,
16421        window: &mut Window,
16422        cx: &mut Context<Self>,
16423    ) {
16424        if !self.diagnostics_enabled() {
16425            return;
16426        }
16427        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16428        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16429    }
16430
16431    pub fn go_to_diagnostic_impl(
16432        &mut self,
16433        direction: Direction,
16434        severity: GoToDiagnosticSeverityFilter,
16435        window: &mut Window,
16436        cx: &mut Context<Self>,
16437    ) {
16438        let buffer = self.buffer.read(cx).snapshot(cx);
16439        let selection = self
16440            .selections
16441            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16442
16443        let mut active_group_id = None;
16444        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16445            && active_group.active_range.start.to_offset(&buffer) == selection.start
16446        {
16447            active_group_id = Some(active_group.group_id);
16448        }
16449
16450        fn filtered<'a>(
16451            severity: GoToDiagnosticSeverityFilter,
16452            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16453        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16454            diagnostics
16455                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16456                .filter(|entry| entry.range.start != entry.range.end)
16457                .filter(|entry| !entry.diagnostic.is_unnecessary)
16458        }
16459
16460        let before = filtered(
16461            severity,
16462            buffer
16463                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16464                .filter(|entry| entry.range.start <= selection.start),
16465        );
16466        let after = filtered(
16467            severity,
16468            buffer
16469                .diagnostics_in_range(selection.start..buffer.len())
16470                .filter(|entry| entry.range.start >= selection.start),
16471        );
16472
16473        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16474        if direction == Direction::Prev {
16475            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16476            {
16477                for diagnostic in prev_diagnostics.into_iter().rev() {
16478                    if diagnostic.range.start != selection.start
16479                        || active_group_id
16480                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16481                    {
16482                        found = Some(diagnostic);
16483                        break 'outer;
16484                    }
16485                }
16486            }
16487        } else {
16488            for diagnostic in after.chain(before) {
16489                if diagnostic.range.start != selection.start
16490                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16491                {
16492                    found = Some(diagnostic);
16493                    break;
16494                }
16495            }
16496        }
16497        let Some(next_diagnostic) = found else {
16498            return;
16499        };
16500
16501        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16502        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16503            return;
16504        };
16505        let snapshot = self.snapshot(window, cx);
16506        if snapshot.intersects_fold(next_diagnostic.range.start) {
16507            self.unfold_ranges(
16508                std::slice::from_ref(&next_diagnostic.range),
16509                true,
16510                false,
16511                cx,
16512            );
16513        }
16514        self.change_selections(Default::default(), window, cx, |s| {
16515            s.select_ranges(vec![
16516                next_diagnostic.range.start..next_diagnostic.range.start,
16517            ])
16518        });
16519        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16520        self.refresh_edit_prediction(false, true, window, cx);
16521    }
16522
16523    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16524        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16525        let snapshot = self.snapshot(window, cx);
16526        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16527        self.go_to_hunk_before_or_after_position(
16528            &snapshot,
16529            selection.head(),
16530            Direction::Next,
16531            window,
16532            cx,
16533        );
16534    }
16535
16536    pub fn go_to_hunk_before_or_after_position(
16537        &mut self,
16538        snapshot: &EditorSnapshot,
16539        position: Point,
16540        direction: Direction,
16541        window: &mut Window,
16542        cx: &mut Context<Editor>,
16543    ) {
16544        let row = if direction == Direction::Next {
16545            self.hunk_after_position(snapshot, position)
16546                .map(|hunk| hunk.row_range.start)
16547        } else {
16548            self.hunk_before_position(snapshot, position)
16549        };
16550
16551        if let Some(row) = row {
16552            let destination = Point::new(row.0, 0);
16553            let autoscroll = Autoscroll::center();
16554
16555            self.unfold_ranges(&[destination..destination], false, false, cx);
16556            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16557                s.select_ranges([destination..destination]);
16558            });
16559        }
16560    }
16561
16562    fn hunk_after_position(
16563        &mut self,
16564        snapshot: &EditorSnapshot,
16565        position: Point,
16566    ) -> Option<MultiBufferDiffHunk> {
16567        snapshot
16568            .buffer_snapshot()
16569            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16570            .find(|hunk| hunk.row_range.start.0 > position.row)
16571            .or_else(|| {
16572                snapshot
16573                    .buffer_snapshot()
16574                    .diff_hunks_in_range(Point::zero()..position)
16575                    .find(|hunk| hunk.row_range.end.0 < position.row)
16576            })
16577    }
16578
16579    fn go_to_prev_hunk(
16580        &mut self,
16581        _: &GoToPreviousHunk,
16582        window: &mut Window,
16583        cx: &mut Context<Self>,
16584    ) {
16585        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16586        let snapshot = self.snapshot(window, cx);
16587        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16588        self.go_to_hunk_before_or_after_position(
16589            &snapshot,
16590            selection.head(),
16591            Direction::Prev,
16592            window,
16593            cx,
16594        );
16595    }
16596
16597    fn hunk_before_position(
16598        &mut self,
16599        snapshot: &EditorSnapshot,
16600        position: Point,
16601    ) -> Option<MultiBufferRow> {
16602        snapshot
16603            .buffer_snapshot()
16604            .diff_hunk_before(position)
16605            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16606    }
16607
16608    fn go_to_next_change(
16609        &mut self,
16610        _: &GoToNextChange,
16611        window: &mut Window,
16612        cx: &mut Context<Self>,
16613    ) {
16614        if let Some(selections) = self
16615            .change_list
16616            .next_change(1, Direction::Next)
16617            .map(|s| s.to_vec())
16618        {
16619            self.change_selections(Default::default(), window, cx, |s| {
16620                let map = s.display_snapshot();
16621                s.select_display_ranges(selections.iter().map(|a| {
16622                    let point = a.to_display_point(&map);
16623                    point..point
16624                }))
16625            })
16626        }
16627    }
16628
16629    fn go_to_previous_change(
16630        &mut self,
16631        _: &GoToPreviousChange,
16632        window: &mut Window,
16633        cx: &mut Context<Self>,
16634    ) {
16635        if let Some(selections) = self
16636            .change_list
16637            .next_change(1, Direction::Prev)
16638            .map(|s| s.to_vec())
16639        {
16640            self.change_selections(Default::default(), window, cx, |s| {
16641                let map = s.display_snapshot();
16642                s.select_display_ranges(selections.iter().map(|a| {
16643                    let point = a.to_display_point(&map);
16644                    point..point
16645                }))
16646            })
16647        }
16648    }
16649
16650    pub fn go_to_next_document_highlight(
16651        &mut self,
16652        _: &GoToNextDocumentHighlight,
16653        window: &mut Window,
16654        cx: &mut Context<Self>,
16655    ) {
16656        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16657    }
16658
16659    pub fn go_to_prev_document_highlight(
16660        &mut self,
16661        _: &GoToPreviousDocumentHighlight,
16662        window: &mut Window,
16663        cx: &mut Context<Self>,
16664    ) {
16665        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16666    }
16667
16668    pub fn go_to_document_highlight_before_or_after_position(
16669        &mut self,
16670        direction: Direction,
16671        window: &mut Window,
16672        cx: &mut Context<Editor>,
16673    ) {
16674        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16675        let snapshot = self.snapshot(window, cx);
16676        let buffer = &snapshot.buffer_snapshot();
16677        let position = self
16678            .selections
16679            .newest::<Point>(&snapshot.display_snapshot)
16680            .head();
16681        let anchor_position = buffer.anchor_after(position);
16682
16683        // Get all document highlights (both read and write)
16684        let mut all_highlights = Vec::new();
16685
16686        if let Some((_, read_highlights)) = self
16687            .background_highlights
16688            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16689        {
16690            all_highlights.extend(read_highlights.iter());
16691        }
16692
16693        if let Some((_, write_highlights)) = self
16694            .background_highlights
16695            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16696        {
16697            all_highlights.extend(write_highlights.iter());
16698        }
16699
16700        if all_highlights.is_empty() {
16701            return;
16702        }
16703
16704        // Sort highlights by position
16705        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16706
16707        let target_highlight = match direction {
16708            Direction::Next => {
16709                // Find the first highlight after the current position
16710                all_highlights
16711                    .iter()
16712                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16713            }
16714            Direction::Prev => {
16715                // Find the last highlight before the current position
16716                all_highlights
16717                    .iter()
16718                    .rev()
16719                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16720            }
16721        };
16722
16723        if let Some(highlight) = target_highlight {
16724            let destination = highlight.start.to_point(buffer);
16725            let autoscroll = Autoscroll::center();
16726
16727            self.unfold_ranges(&[destination..destination], false, false, cx);
16728            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16729                s.select_ranges([destination..destination]);
16730            });
16731        }
16732    }
16733
16734    fn go_to_line<T: 'static>(
16735        &mut self,
16736        position: Anchor,
16737        highlight_color: Option<Hsla>,
16738        window: &mut Window,
16739        cx: &mut Context<Self>,
16740    ) {
16741        let snapshot = self.snapshot(window, cx).display_snapshot;
16742        let position = position.to_point(&snapshot.buffer_snapshot());
16743        let start = snapshot
16744            .buffer_snapshot()
16745            .clip_point(Point::new(position.row, 0), Bias::Left);
16746        let end = start + Point::new(1, 0);
16747        let start = snapshot.buffer_snapshot().anchor_before(start);
16748        let end = snapshot.buffer_snapshot().anchor_before(end);
16749
16750        self.highlight_rows::<T>(
16751            start..end,
16752            highlight_color
16753                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16754            Default::default(),
16755            cx,
16756        );
16757
16758        if self.buffer.read(cx).is_singleton() {
16759            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16760        }
16761    }
16762
16763    pub fn go_to_definition(
16764        &mut self,
16765        _: &GoToDefinition,
16766        window: &mut Window,
16767        cx: &mut Context<Self>,
16768    ) -> Task<Result<Navigated>> {
16769        let definition =
16770            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16771        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16772        cx.spawn_in(window, async move |editor, cx| {
16773            if definition.await? == Navigated::Yes {
16774                return Ok(Navigated::Yes);
16775            }
16776            match fallback_strategy {
16777                GoToDefinitionFallback::None => Ok(Navigated::No),
16778                GoToDefinitionFallback::FindAllReferences => {
16779                    match editor.update_in(cx, |editor, window, cx| {
16780                        editor.find_all_references(&FindAllReferences, window, cx)
16781                    })? {
16782                        Some(references) => references.await,
16783                        None => Ok(Navigated::No),
16784                    }
16785                }
16786            }
16787        })
16788    }
16789
16790    pub fn go_to_declaration(
16791        &mut self,
16792        _: &GoToDeclaration,
16793        window: &mut Window,
16794        cx: &mut Context<Self>,
16795    ) -> Task<Result<Navigated>> {
16796        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16797    }
16798
16799    pub fn go_to_declaration_split(
16800        &mut self,
16801        _: &GoToDeclaration,
16802        window: &mut Window,
16803        cx: &mut Context<Self>,
16804    ) -> Task<Result<Navigated>> {
16805        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16806    }
16807
16808    pub fn go_to_implementation(
16809        &mut self,
16810        _: &GoToImplementation,
16811        window: &mut Window,
16812        cx: &mut Context<Self>,
16813    ) -> Task<Result<Navigated>> {
16814        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16815    }
16816
16817    pub fn go_to_implementation_split(
16818        &mut self,
16819        _: &GoToImplementationSplit,
16820        window: &mut Window,
16821        cx: &mut Context<Self>,
16822    ) -> Task<Result<Navigated>> {
16823        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16824    }
16825
16826    pub fn go_to_type_definition(
16827        &mut self,
16828        _: &GoToTypeDefinition,
16829        window: &mut Window,
16830        cx: &mut Context<Self>,
16831    ) -> Task<Result<Navigated>> {
16832        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16833    }
16834
16835    pub fn go_to_definition_split(
16836        &mut self,
16837        _: &GoToDefinitionSplit,
16838        window: &mut Window,
16839        cx: &mut Context<Self>,
16840    ) -> Task<Result<Navigated>> {
16841        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16842    }
16843
16844    pub fn go_to_type_definition_split(
16845        &mut self,
16846        _: &GoToTypeDefinitionSplit,
16847        window: &mut Window,
16848        cx: &mut Context<Self>,
16849    ) -> Task<Result<Navigated>> {
16850        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16851    }
16852
16853    fn go_to_definition_of_kind(
16854        &mut self,
16855        kind: GotoDefinitionKind,
16856        split: bool,
16857        window: &mut Window,
16858        cx: &mut Context<Self>,
16859    ) -> Task<Result<Navigated>> {
16860        let Some(provider) = self.semantics_provider.clone() else {
16861            return Task::ready(Ok(Navigated::No));
16862        };
16863        let head = self
16864            .selections
16865            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
16866            .head();
16867        let buffer = self.buffer.read(cx);
16868        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16869            return Task::ready(Ok(Navigated::No));
16870        };
16871        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16872            return Task::ready(Ok(Navigated::No));
16873        };
16874
16875        cx.spawn_in(window, async move |editor, cx| {
16876            let Some(definitions) = definitions.await? else {
16877                return Ok(Navigated::No);
16878            };
16879            let navigated = editor
16880                .update_in(cx, |editor, window, cx| {
16881                    editor.navigate_to_hover_links(
16882                        Some(kind),
16883                        definitions
16884                            .into_iter()
16885                            .filter(|location| {
16886                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16887                            })
16888                            .map(HoverLink::Text)
16889                            .collect::<Vec<_>>(),
16890                        split,
16891                        window,
16892                        cx,
16893                    )
16894                })?
16895                .await?;
16896            anyhow::Ok(navigated)
16897        })
16898    }
16899
16900    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16901        let selection = self.selections.newest_anchor();
16902        let head = selection.head();
16903        let tail = selection.tail();
16904
16905        let Some((buffer, start_position)) =
16906            self.buffer.read(cx).text_anchor_for_position(head, cx)
16907        else {
16908            return;
16909        };
16910
16911        let end_position = if head != tail {
16912            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16913                return;
16914            };
16915            Some(pos)
16916        } else {
16917            None
16918        };
16919
16920        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16921            let url = if let Some(end_pos) = end_position {
16922                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16923            } else {
16924                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16925            };
16926
16927            if let Some(url) = url {
16928                cx.update(|window, cx| {
16929                    if parse_zed_link(&url, cx).is_some() {
16930                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16931                    } else {
16932                        cx.open_url(&url);
16933                    }
16934                })?;
16935            }
16936
16937            anyhow::Ok(())
16938        });
16939
16940        url_finder.detach();
16941    }
16942
16943    pub fn open_selected_filename(
16944        &mut self,
16945        _: &OpenSelectedFilename,
16946        window: &mut Window,
16947        cx: &mut Context<Self>,
16948    ) {
16949        let Some(workspace) = self.workspace() else {
16950            return;
16951        };
16952
16953        let position = self.selections.newest_anchor().head();
16954
16955        let Some((buffer, buffer_position)) =
16956            self.buffer.read(cx).text_anchor_for_position(position, cx)
16957        else {
16958            return;
16959        };
16960
16961        let project = self.project.clone();
16962
16963        cx.spawn_in(window, async move |_, cx| {
16964            let result = find_file(&buffer, project, buffer_position, cx).await;
16965
16966            if let Some((_, path)) = result {
16967                workspace
16968                    .update_in(cx, |workspace, window, cx| {
16969                        workspace.open_resolved_path(path, window, cx)
16970                    })?
16971                    .await?;
16972            }
16973            anyhow::Ok(())
16974        })
16975        .detach();
16976    }
16977
16978    pub(crate) fn navigate_to_hover_links(
16979        &mut self,
16980        kind: Option<GotoDefinitionKind>,
16981        definitions: Vec<HoverLink>,
16982        split: bool,
16983        window: &mut Window,
16984        cx: &mut Context<Editor>,
16985    ) -> Task<Result<Navigated>> {
16986        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16987        let mut first_url_or_file = None;
16988        let definitions: Vec<_> = definitions
16989            .into_iter()
16990            .filter_map(|def| match def {
16991                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16992                HoverLink::InlayHint(lsp_location, server_id) => {
16993                    let computation =
16994                        self.compute_target_location(lsp_location, server_id, window, cx);
16995                    Some(cx.background_spawn(computation))
16996                }
16997                HoverLink::Url(url) => {
16998                    first_url_or_file = Some(Either::Left(url));
16999                    None
17000                }
17001                HoverLink::File(path) => {
17002                    first_url_or_file = Some(Either::Right(path));
17003                    None
17004                }
17005            })
17006            .collect();
17007
17008        let workspace = self.workspace();
17009
17010        cx.spawn_in(window, async move |editor, cx| {
17011            let locations: Vec<Location> = future::join_all(definitions)
17012                .await
17013                .into_iter()
17014                .filter_map(|location| location.transpose())
17015                .collect::<Result<_>>()
17016                .context("location tasks")?;
17017            let mut locations = cx.update(|_, cx| {
17018                locations
17019                    .into_iter()
17020                    .map(|location| {
17021                        let buffer = location.buffer.read(cx);
17022                        (location.buffer, location.range.to_point(buffer))
17023                    })
17024                    .into_group_map()
17025            })?;
17026            let mut num_locations = 0;
17027            for ranges in locations.values_mut() {
17028                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17029                ranges.dedup();
17030                num_locations += ranges.len();
17031            }
17032
17033            if num_locations > 1 {
17034                let Some(workspace) = workspace else {
17035                    return Ok(Navigated::No);
17036                };
17037
17038                let tab_kind = match kind {
17039                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17040                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17041                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17042                    Some(GotoDefinitionKind::Type) => "Types",
17043                };
17044                let title = editor
17045                    .update_in(cx, |_, _, cx| {
17046                        let target = locations
17047                            .iter()
17048                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17049                            .map(|(buffer, location)| {
17050                                buffer
17051                                    .read(cx)
17052                                    .text_for_range(location.clone())
17053                                    .collect::<String>()
17054                            })
17055                            .filter(|text| !text.contains('\n'))
17056                            .unique()
17057                            .take(3)
17058                            .join(", ");
17059                        if target.is_empty() {
17060                            tab_kind.to_owned()
17061                        } else {
17062                            format!("{tab_kind} for {target}")
17063                        }
17064                    })
17065                    .context("buffer title")?;
17066
17067                let opened = workspace
17068                    .update_in(cx, |workspace, window, cx| {
17069                        Self::open_locations_in_multibuffer(
17070                            workspace,
17071                            locations,
17072                            title,
17073                            split,
17074                            MultibufferSelectionMode::First,
17075                            window,
17076                            cx,
17077                        )
17078                    })
17079                    .is_ok();
17080
17081                anyhow::Ok(Navigated::from_bool(opened))
17082            } else if num_locations == 0 {
17083                // If there is one url or file, open it directly
17084                match first_url_or_file {
17085                    Some(Either::Left(url)) => {
17086                        cx.update(|_, cx| cx.open_url(&url))?;
17087                        Ok(Navigated::Yes)
17088                    }
17089                    Some(Either::Right(path)) => {
17090                        let Some(workspace) = workspace else {
17091                            return Ok(Navigated::No);
17092                        };
17093
17094                        workspace
17095                            .update_in(cx, |workspace, window, cx| {
17096                                workspace.open_resolved_path(path, window, cx)
17097                            })?
17098                            .await?;
17099                        Ok(Navigated::Yes)
17100                    }
17101                    None => Ok(Navigated::No),
17102                }
17103            } else {
17104                let Some(workspace) = workspace else {
17105                    return Ok(Navigated::No);
17106                };
17107
17108                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17109                let target_range = target_ranges.first().unwrap().clone();
17110
17111                editor.update_in(cx, |editor, window, cx| {
17112                    let range = target_range.to_point(target_buffer.read(cx));
17113                    let range = editor.range_for_match(&range);
17114                    let range = collapse_multiline_range(range);
17115
17116                    if !split
17117                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17118                    {
17119                        editor.go_to_singleton_buffer_range(range, window, cx);
17120                    } else {
17121                        let pane = workspace.read(cx).active_pane().clone();
17122                        window.defer(cx, move |window, cx| {
17123                            let target_editor: Entity<Self> =
17124                                workspace.update(cx, |workspace, cx| {
17125                                    let pane = if split {
17126                                        workspace.adjacent_pane(window, cx)
17127                                    } else {
17128                                        workspace.active_pane().clone()
17129                                    };
17130
17131                                    workspace.open_project_item(
17132                                        pane,
17133                                        target_buffer.clone(),
17134                                        true,
17135                                        true,
17136                                        window,
17137                                        cx,
17138                                    )
17139                                });
17140                            target_editor.update(cx, |target_editor, cx| {
17141                                // When selecting a definition in a different buffer, disable the nav history
17142                                // to avoid creating a history entry at the previous cursor location.
17143                                pane.update(cx, |pane, _| pane.disable_history());
17144                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17145                                pane.update(cx, |pane, _| pane.enable_history());
17146                            });
17147                        });
17148                    }
17149                    Navigated::Yes
17150                })
17151            }
17152        })
17153    }
17154
17155    fn compute_target_location(
17156        &self,
17157        lsp_location: lsp::Location,
17158        server_id: LanguageServerId,
17159        window: &mut Window,
17160        cx: &mut Context<Self>,
17161    ) -> Task<anyhow::Result<Option<Location>>> {
17162        let Some(project) = self.project.clone() else {
17163            return Task::ready(Ok(None));
17164        };
17165
17166        cx.spawn_in(window, async move |editor, cx| {
17167            let location_task = editor.update(cx, |_, cx| {
17168                project.update(cx, |project, cx| {
17169                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17170                })
17171            })?;
17172            let location = Some({
17173                let target_buffer_handle = location_task.await.context("open local buffer")?;
17174                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17175                    let target_start = target_buffer
17176                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17177                    let target_end = target_buffer
17178                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17179                    target_buffer.anchor_after(target_start)
17180                        ..target_buffer.anchor_before(target_end)
17181                })?;
17182                Location {
17183                    buffer: target_buffer_handle,
17184                    range,
17185                }
17186            });
17187            Ok(location)
17188        })
17189    }
17190
17191    fn go_to_next_reference(
17192        &mut self,
17193        _: &GoToNextReference,
17194        window: &mut Window,
17195        cx: &mut Context<Self>,
17196    ) {
17197        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17198        if let Some(task) = task {
17199            task.detach();
17200        };
17201    }
17202
17203    fn go_to_prev_reference(
17204        &mut self,
17205        _: &GoToPreviousReference,
17206        window: &mut Window,
17207        cx: &mut Context<Self>,
17208    ) {
17209        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17210        if let Some(task) = task {
17211            task.detach();
17212        };
17213    }
17214
17215    pub fn go_to_reference_before_or_after_position(
17216        &mut self,
17217        direction: Direction,
17218        count: usize,
17219        window: &mut Window,
17220        cx: &mut Context<Self>,
17221    ) -> Option<Task<Result<()>>> {
17222        let selection = self.selections.newest_anchor();
17223        let head = selection.head();
17224
17225        let multi_buffer = self.buffer.read(cx);
17226
17227        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17228        let workspace = self.workspace()?;
17229        let project = workspace.read(cx).project().clone();
17230        let references =
17231            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17232        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17233            let Some(locations) = references.await? else {
17234                return Ok(());
17235            };
17236
17237            if locations.is_empty() {
17238                // totally normal - the cursor may be on something which is not
17239                // a symbol (e.g. a keyword)
17240                log::info!("no references found under cursor");
17241                return Ok(());
17242            }
17243
17244            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17245
17246            let (locations, current_location_index) =
17247                multi_buffer.update(cx, |multi_buffer, cx| {
17248                    let mut locations = locations
17249                        .into_iter()
17250                        .filter_map(|loc| {
17251                            let start = multi_buffer.buffer_anchor_to_anchor(
17252                                &loc.buffer,
17253                                loc.range.start,
17254                                cx,
17255                            )?;
17256                            let end = multi_buffer.buffer_anchor_to_anchor(
17257                                &loc.buffer,
17258                                loc.range.end,
17259                                cx,
17260                            )?;
17261                            Some(start..end)
17262                        })
17263                        .collect::<Vec<_>>();
17264
17265                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17266                    // There is an O(n) implementation, but given this list will be
17267                    // small (usually <100 items), the extra O(log(n)) factor isn't
17268                    // worth the (surprisingly large amount of) extra complexity.
17269                    locations
17270                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17271
17272                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17273
17274                    let current_location_index = locations.iter().position(|loc| {
17275                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17276                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17277                    });
17278
17279                    (locations, current_location_index)
17280                })?;
17281
17282            let Some(current_location_index) = current_location_index else {
17283                // This indicates something has gone wrong, because we already
17284                // handle the "no references" case above
17285                log::error!(
17286                    "failed to find current reference under cursor. Total references: {}",
17287                    locations.len()
17288                );
17289                return Ok(());
17290            };
17291
17292            let destination_location_index = match direction {
17293                Direction::Next => (current_location_index + count) % locations.len(),
17294                Direction::Prev => {
17295                    (current_location_index + locations.len() - count % locations.len())
17296                        % locations.len()
17297                }
17298            };
17299
17300            // TODO(cameron): is this needed?
17301            // the thinking is to avoid "jumping to the current location" (avoid
17302            // polluting "jumplist" in vim terms)
17303            if current_location_index == destination_location_index {
17304                return Ok(());
17305            }
17306
17307            let Range { start, end } = locations[destination_location_index];
17308
17309            editor.update_in(cx, |editor, window, cx| {
17310                let effects = SelectionEffects::default();
17311
17312                editor.unfold_ranges(&[start..end], false, false, cx);
17313                editor.change_selections(effects, window, cx, |s| {
17314                    s.select_ranges([start..start]);
17315                });
17316            })?;
17317
17318            Ok(())
17319        }))
17320    }
17321
17322    pub fn find_all_references(
17323        &mut self,
17324        _: &FindAllReferences,
17325        window: &mut Window,
17326        cx: &mut Context<Self>,
17327    ) -> Option<Task<Result<Navigated>>> {
17328        let selection = self
17329            .selections
17330            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17331        let multi_buffer = self.buffer.read(cx);
17332        let head = selection.head();
17333
17334        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17335        let head_anchor = multi_buffer_snapshot.anchor_at(
17336            head,
17337            if head < selection.tail() {
17338                Bias::Right
17339            } else {
17340                Bias::Left
17341            },
17342        );
17343
17344        match self
17345            .find_all_references_task_sources
17346            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17347        {
17348            Ok(_) => {
17349                log::info!(
17350                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17351                );
17352                return None;
17353            }
17354            Err(i) => {
17355                self.find_all_references_task_sources.insert(i, head_anchor);
17356            }
17357        }
17358
17359        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17360        let workspace = self.workspace()?;
17361        let project = workspace.read(cx).project().clone();
17362        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17363        Some(cx.spawn_in(window, async move |editor, cx| {
17364            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17365                if let Ok(i) = editor
17366                    .find_all_references_task_sources
17367                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17368                {
17369                    editor.find_all_references_task_sources.remove(i);
17370                }
17371            });
17372
17373            let Some(locations) = references.await? else {
17374                return anyhow::Ok(Navigated::No);
17375            };
17376            let mut locations = cx.update(|_, cx| {
17377                locations
17378                    .into_iter()
17379                    .map(|location| {
17380                        let buffer = location.buffer.read(cx);
17381                        (location.buffer, location.range.to_point(buffer))
17382                    })
17383                    .into_group_map()
17384            })?;
17385            if locations.is_empty() {
17386                return anyhow::Ok(Navigated::No);
17387            }
17388            for ranges in locations.values_mut() {
17389                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17390                ranges.dedup();
17391            }
17392
17393            workspace.update_in(cx, |workspace, window, cx| {
17394                let target = locations
17395                    .iter()
17396                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17397                    .map(|(buffer, location)| {
17398                        buffer
17399                            .read(cx)
17400                            .text_for_range(location.clone())
17401                            .collect::<String>()
17402                    })
17403                    .filter(|text| !text.contains('\n'))
17404                    .unique()
17405                    .take(3)
17406                    .join(", ");
17407                let title = if target.is_empty() {
17408                    "References".to_owned()
17409                } else {
17410                    format!("References to {target}")
17411                };
17412                Self::open_locations_in_multibuffer(
17413                    workspace,
17414                    locations,
17415                    title,
17416                    false,
17417                    MultibufferSelectionMode::First,
17418                    window,
17419                    cx,
17420                );
17421                Navigated::Yes
17422            })
17423        }))
17424    }
17425
17426    /// Opens a multibuffer with the given project locations in it
17427    pub fn open_locations_in_multibuffer(
17428        workspace: &mut Workspace,
17429        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17430        title: String,
17431        split: bool,
17432        multibuffer_selection_mode: MultibufferSelectionMode,
17433        window: &mut Window,
17434        cx: &mut Context<Workspace>,
17435    ) {
17436        if locations.is_empty() {
17437            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17438            return;
17439        }
17440
17441        let capability = workspace.project().read(cx).capability();
17442        let mut ranges = <Vec<Range<Anchor>>>::new();
17443
17444        // a key to find existing multibuffer editors with the same set of locations
17445        // to prevent us from opening more and more multibuffer tabs for searches and the like
17446        let mut key = (title.clone(), vec![]);
17447        let excerpt_buffer = cx.new(|cx| {
17448            let key = &mut key.1;
17449            let mut multibuffer = MultiBuffer::new(capability);
17450            for (buffer, mut ranges_for_buffer) in locations {
17451                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17452                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17453                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17454                    PathKey::for_buffer(&buffer, cx),
17455                    buffer.clone(),
17456                    ranges_for_buffer,
17457                    multibuffer_context_lines(cx),
17458                    cx,
17459                );
17460                ranges.extend(new_ranges)
17461            }
17462
17463            multibuffer.with_title(title)
17464        });
17465        let existing = workspace.active_pane().update(cx, |pane, cx| {
17466            pane.items()
17467                .filter_map(|item| item.downcast::<Editor>())
17468                .find(|editor| {
17469                    editor
17470                        .read(cx)
17471                        .lookup_key
17472                        .as_ref()
17473                        .and_then(|it| {
17474                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17475                        })
17476                        .is_some_and(|it| *it == key)
17477                })
17478        });
17479        let editor = existing.unwrap_or_else(|| {
17480            cx.new(|cx| {
17481                let mut editor = Editor::for_multibuffer(
17482                    excerpt_buffer,
17483                    Some(workspace.project().clone()),
17484                    window,
17485                    cx,
17486                );
17487                editor.lookup_key = Some(Box::new(key));
17488                editor
17489            })
17490        });
17491        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17492            MultibufferSelectionMode::First => {
17493                if let Some(first_range) = ranges.first() {
17494                    editor.change_selections(
17495                        SelectionEffects::no_scroll(),
17496                        window,
17497                        cx,
17498                        |selections| {
17499                            selections.clear_disjoint();
17500                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17501                        },
17502                    );
17503                }
17504                editor.highlight_background::<Self>(
17505                    &ranges,
17506                    |theme| theme.colors().editor_highlighted_line_background,
17507                    cx,
17508                );
17509            }
17510            MultibufferSelectionMode::All => {
17511                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17512                    selections.clear_disjoint();
17513                    selections.select_anchor_ranges(ranges);
17514                });
17515            }
17516        });
17517
17518        let item = Box::new(editor);
17519        let item_id = item.item_id();
17520
17521        if split {
17522            let pane = workspace.adjacent_pane(window, cx);
17523            workspace.add_item(pane, item, None, true, true, window, cx);
17524        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17525            let (preview_item_id, preview_item_idx) =
17526                workspace.active_pane().read_with(cx, |pane, _| {
17527                    (pane.preview_item_id(), pane.preview_item_idx())
17528                });
17529
17530            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17531
17532            if let Some(preview_item_id) = preview_item_id {
17533                workspace.active_pane().update(cx, |pane, cx| {
17534                    pane.remove_item(preview_item_id, false, false, window, cx);
17535                });
17536            }
17537        } else {
17538            workspace.add_item_to_active_pane(item, None, true, window, cx);
17539        }
17540        workspace.active_pane().update(cx, |pane, cx| {
17541            pane.set_preview_item_id(Some(item_id), cx);
17542        });
17543    }
17544
17545    pub fn rename(
17546        &mut self,
17547        _: &Rename,
17548        window: &mut Window,
17549        cx: &mut Context<Self>,
17550    ) -> Option<Task<Result<()>>> {
17551        use language::ToOffset as _;
17552
17553        let provider = self.semantics_provider.clone()?;
17554        let selection = self.selections.newest_anchor().clone();
17555        let (cursor_buffer, cursor_buffer_position) = self
17556            .buffer
17557            .read(cx)
17558            .text_anchor_for_position(selection.head(), cx)?;
17559        let (tail_buffer, cursor_buffer_position_end) = self
17560            .buffer
17561            .read(cx)
17562            .text_anchor_for_position(selection.tail(), cx)?;
17563        if tail_buffer != cursor_buffer {
17564            return None;
17565        }
17566
17567        let snapshot = cursor_buffer.read(cx).snapshot();
17568        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17569        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17570        let prepare_rename = provider
17571            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17572            .unwrap_or_else(|| Task::ready(Ok(None)));
17573        drop(snapshot);
17574
17575        Some(cx.spawn_in(window, async move |this, cx| {
17576            let rename_range = if let Some(range) = prepare_rename.await? {
17577                Some(range)
17578            } else {
17579                this.update(cx, |this, cx| {
17580                    let buffer = this.buffer.read(cx).snapshot(cx);
17581                    let mut buffer_highlights = this
17582                        .document_highlights_for_position(selection.head(), &buffer)
17583                        .filter(|highlight| {
17584                            highlight.start.excerpt_id == selection.head().excerpt_id
17585                                && highlight.end.excerpt_id == selection.head().excerpt_id
17586                        });
17587                    buffer_highlights
17588                        .next()
17589                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17590                })?
17591            };
17592            if let Some(rename_range) = rename_range {
17593                this.update_in(cx, |this, window, cx| {
17594                    let snapshot = cursor_buffer.read(cx).snapshot();
17595                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17596                    let cursor_offset_in_rename_range =
17597                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17598                    let cursor_offset_in_rename_range_end =
17599                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17600
17601                    this.take_rename(false, window, cx);
17602                    let buffer = this.buffer.read(cx).read(cx);
17603                    let cursor_offset = selection.head().to_offset(&buffer);
17604                    let rename_start =
17605                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17606                    let rename_end = rename_start + rename_buffer_range.len();
17607                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17608                    let mut old_highlight_id = None;
17609                    let old_name: Arc<str> = buffer
17610                        .chunks(rename_start..rename_end, true)
17611                        .map(|chunk| {
17612                            if old_highlight_id.is_none() {
17613                                old_highlight_id = chunk.syntax_highlight_id;
17614                            }
17615                            chunk.text
17616                        })
17617                        .collect::<String>()
17618                        .into();
17619
17620                    drop(buffer);
17621
17622                    // Position the selection in the rename editor so that it matches the current selection.
17623                    this.show_local_selections = false;
17624                    let rename_editor = cx.new(|cx| {
17625                        let mut editor = Editor::single_line(window, cx);
17626                        editor.buffer.update(cx, |buffer, cx| {
17627                            buffer.edit(
17628                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17629                                None,
17630                                cx,
17631                            )
17632                        });
17633                        let cursor_offset_in_rename_range =
17634                            MultiBufferOffset(cursor_offset_in_rename_range);
17635                        let cursor_offset_in_rename_range_end =
17636                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17637                        let rename_selection_range = match cursor_offset_in_rename_range
17638                            .cmp(&cursor_offset_in_rename_range_end)
17639                        {
17640                            Ordering::Equal => {
17641                                editor.select_all(&SelectAll, window, cx);
17642                                return editor;
17643                            }
17644                            Ordering::Less => {
17645                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17646                            }
17647                            Ordering::Greater => {
17648                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17649                            }
17650                        };
17651                        if rename_selection_range.end.0 > old_name.len() {
17652                            editor.select_all(&SelectAll, window, cx);
17653                        } else {
17654                            editor.change_selections(Default::default(), window, cx, |s| {
17655                                s.select_ranges([rename_selection_range]);
17656                            });
17657                        }
17658                        editor
17659                    });
17660                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17661                        if e == &EditorEvent::Focused {
17662                            cx.emit(EditorEvent::FocusedIn)
17663                        }
17664                    })
17665                    .detach();
17666
17667                    let write_highlights =
17668                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17669                    let read_highlights =
17670                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17671                    let ranges = write_highlights
17672                        .iter()
17673                        .flat_map(|(_, ranges)| ranges.iter())
17674                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17675                        .cloned()
17676                        .collect();
17677
17678                    this.highlight_text::<Rename>(
17679                        ranges,
17680                        HighlightStyle {
17681                            fade_out: Some(0.6),
17682                            ..Default::default()
17683                        },
17684                        cx,
17685                    );
17686                    let rename_focus_handle = rename_editor.focus_handle(cx);
17687                    window.focus(&rename_focus_handle);
17688                    let block_id = this.insert_blocks(
17689                        [BlockProperties {
17690                            style: BlockStyle::Flex,
17691                            placement: BlockPlacement::Below(range.start),
17692                            height: Some(1),
17693                            render: Arc::new({
17694                                let rename_editor = rename_editor.clone();
17695                                move |cx: &mut BlockContext| {
17696                                    let mut text_style = cx.editor_style.text.clone();
17697                                    if let Some(highlight_style) = old_highlight_id
17698                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17699                                    {
17700                                        text_style = text_style.highlight(highlight_style);
17701                                    }
17702                                    div()
17703                                        .block_mouse_except_scroll()
17704                                        .pl(cx.anchor_x)
17705                                        .child(EditorElement::new(
17706                                            &rename_editor,
17707                                            EditorStyle {
17708                                                background: cx.theme().system().transparent,
17709                                                local_player: cx.editor_style.local_player,
17710                                                text: text_style,
17711                                                scrollbar_width: cx.editor_style.scrollbar_width,
17712                                                syntax: cx.editor_style.syntax.clone(),
17713                                                status: cx.editor_style.status.clone(),
17714                                                inlay_hints_style: HighlightStyle {
17715                                                    font_weight: Some(FontWeight::BOLD),
17716                                                    ..make_inlay_hints_style(cx.app)
17717                                                },
17718                                                edit_prediction_styles: make_suggestion_styles(
17719                                                    cx.app,
17720                                                ),
17721                                                ..EditorStyle::default()
17722                                            },
17723                                        ))
17724                                        .into_any_element()
17725                                }
17726                            }),
17727                            priority: 0,
17728                        }],
17729                        Some(Autoscroll::fit()),
17730                        cx,
17731                    )[0];
17732                    this.pending_rename = Some(RenameState {
17733                        range,
17734                        old_name,
17735                        editor: rename_editor,
17736                        block_id,
17737                    });
17738                })?;
17739            }
17740
17741            Ok(())
17742        }))
17743    }
17744
17745    pub fn confirm_rename(
17746        &mut self,
17747        _: &ConfirmRename,
17748        window: &mut Window,
17749        cx: &mut Context<Self>,
17750    ) -> Option<Task<Result<()>>> {
17751        let rename = self.take_rename(false, window, cx)?;
17752        let workspace = self.workspace()?.downgrade();
17753        let (buffer, start) = self
17754            .buffer
17755            .read(cx)
17756            .text_anchor_for_position(rename.range.start, cx)?;
17757        let (end_buffer, _) = self
17758            .buffer
17759            .read(cx)
17760            .text_anchor_for_position(rename.range.end, cx)?;
17761        if buffer != end_buffer {
17762            return None;
17763        }
17764
17765        let old_name = rename.old_name;
17766        let new_name = rename.editor.read(cx).text(cx);
17767
17768        let rename = self.semantics_provider.as_ref()?.perform_rename(
17769            &buffer,
17770            start,
17771            new_name.clone(),
17772            cx,
17773        )?;
17774
17775        Some(cx.spawn_in(window, async move |editor, cx| {
17776            let project_transaction = rename.await?;
17777            Self::open_project_transaction(
17778                &editor,
17779                workspace,
17780                project_transaction,
17781                format!("Rename: {}{}", old_name, new_name),
17782                cx,
17783            )
17784            .await?;
17785
17786            editor.update(cx, |editor, cx| {
17787                editor.refresh_document_highlights(cx);
17788            })?;
17789            Ok(())
17790        }))
17791    }
17792
17793    fn take_rename(
17794        &mut self,
17795        moving_cursor: bool,
17796        window: &mut Window,
17797        cx: &mut Context<Self>,
17798    ) -> Option<RenameState> {
17799        let rename = self.pending_rename.take()?;
17800        if rename.editor.focus_handle(cx).is_focused(window) {
17801            window.focus(&self.focus_handle);
17802        }
17803
17804        self.remove_blocks(
17805            [rename.block_id].into_iter().collect(),
17806            Some(Autoscroll::fit()),
17807            cx,
17808        );
17809        self.clear_highlights::<Rename>(cx);
17810        self.show_local_selections = true;
17811
17812        if moving_cursor {
17813            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17814                editor
17815                    .selections
17816                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
17817                    .head()
17818            });
17819
17820            // Update the selection to match the position of the selection inside
17821            // the rename editor.
17822            let snapshot = self.buffer.read(cx).read(cx);
17823            let rename_range = rename.range.to_offset(&snapshot);
17824            let cursor_in_editor = snapshot
17825                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17826                .min(rename_range.end);
17827            drop(snapshot);
17828
17829            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17830                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17831            });
17832        } else {
17833            self.refresh_document_highlights(cx);
17834        }
17835
17836        Some(rename)
17837    }
17838
17839    pub fn pending_rename(&self) -> Option<&RenameState> {
17840        self.pending_rename.as_ref()
17841    }
17842
17843    fn format(
17844        &mut self,
17845        _: &Format,
17846        window: &mut Window,
17847        cx: &mut Context<Self>,
17848    ) -> Option<Task<Result<()>>> {
17849        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17850
17851        let project = match &self.project {
17852            Some(project) => project.clone(),
17853            None => return None,
17854        };
17855
17856        Some(self.perform_format(
17857            project,
17858            FormatTrigger::Manual,
17859            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17860            window,
17861            cx,
17862        ))
17863    }
17864
17865    fn format_selections(
17866        &mut self,
17867        _: &FormatSelections,
17868        window: &mut Window,
17869        cx: &mut Context<Self>,
17870    ) -> Option<Task<Result<()>>> {
17871        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17872
17873        let project = match &self.project {
17874            Some(project) => project.clone(),
17875            None => return None,
17876        };
17877
17878        let ranges = self
17879            .selections
17880            .all_adjusted(&self.display_snapshot(cx))
17881            .into_iter()
17882            .map(|selection| selection.range())
17883            .collect_vec();
17884
17885        Some(self.perform_format(
17886            project,
17887            FormatTrigger::Manual,
17888            FormatTarget::Ranges(ranges),
17889            window,
17890            cx,
17891        ))
17892    }
17893
17894    fn perform_format(
17895        &mut self,
17896        project: Entity<Project>,
17897        trigger: FormatTrigger,
17898        target: FormatTarget,
17899        window: &mut Window,
17900        cx: &mut Context<Self>,
17901    ) -> Task<Result<()>> {
17902        let buffer = self.buffer.clone();
17903        let (buffers, target) = match target {
17904            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17905            FormatTarget::Ranges(selection_ranges) => {
17906                let multi_buffer = buffer.read(cx);
17907                let snapshot = multi_buffer.read(cx);
17908                let mut buffers = HashSet::default();
17909                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17910                    BTreeMap::new();
17911                for selection_range in selection_ranges {
17912                    for (buffer, buffer_range, _) in
17913                        snapshot.range_to_buffer_ranges(selection_range)
17914                    {
17915                        let buffer_id = buffer.remote_id();
17916                        let start = buffer.anchor_before(buffer_range.start);
17917                        let end = buffer.anchor_after(buffer_range.end);
17918                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17919                        buffer_id_to_ranges
17920                            .entry(buffer_id)
17921                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17922                            .or_insert_with(|| vec![start..end]);
17923                    }
17924                }
17925                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17926            }
17927        };
17928
17929        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17930        let selections_prev = transaction_id_prev
17931            .and_then(|transaction_id_prev| {
17932                // default to selections as they were after the last edit, if we have them,
17933                // instead of how they are now.
17934                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17935                // will take you back to where you made the last edit, instead of staying where you scrolled
17936                self.selection_history
17937                    .transaction(transaction_id_prev)
17938                    .map(|t| t.0.clone())
17939            })
17940            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17941
17942        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17943        let format = project.update(cx, |project, cx| {
17944            project.format(buffers, target, true, trigger, cx)
17945        });
17946
17947        cx.spawn_in(window, async move |editor, cx| {
17948            let transaction = futures::select_biased! {
17949                transaction = format.log_err().fuse() => transaction,
17950                () = timeout => {
17951                    log::warn!("timed out waiting for formatting");
17952                    None
17953                }
17954            };
17955
17956            buffer
17957                .update(cx, |buffer, cx| {
17958                    if let Some(transaction) = transaction
17959                        && !buffer.is_singleton()
17960                    {
17961                        buffer.push_transaction(&transaction.0, cx);
17962                    }
17963                    cx.notify();
17964                })
17965                .ok();
17966
17967            if let Some(transaction_id_now) =
17968                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17969            {
17970                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17971                if has_new_transaction {
17972                    _ = editor.update(cx, |editor, _| {
17973                        editor
17974                            .selection_history
17975                            .insert_transaction(transaction_id_now, selections_prev);
17976                    });
17977                }
17978            }
17979
17980            Ok(())
17981        })
17982    }
17983
17984    fn organize_imports(
17985        &mut self,
17986        _: &OrganizeImports,
17987        window: &mut Window,
17988        cx: &mut Context<Self>,
17989    ) -> Option<Task<Result<()>>> {
17990        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17991        let project = match &self.project {
17992            Some(project) => project.clone(),
17993            None => return None,
17994        };
17995        Some(self.perform_code_action_kind(
17996            project,
17997            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17998            window,
17999            cx,
18000        ))
18001    }
18002
18003    fn perform_code_action_kind(
18004        &mut self,
18005        project: Entity<Project>,
18006        kind: CodeActionKind,
18007        window: &mut Window,
18008        cx: &mut Context<Self>,
18009    ) -> Task<Result<()>> {
18010        let buffer = self.buffer.clone();
18011        let buffers = buffer.read(cx).all_buffers();
18012        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18013        let apply_action = project.update(cx, |project, cx| {
18014            project.apply_code_action_kind(buffers, kind, true, cx)
18015        });
18016        cx.spawn_in(window, async move |_, cx| {
18017            let transaction = futures::select_biased! {
18018                () = timeout => {
18019                    log::warn!("timed out waiting for executing code action");
18020                    None
18021                }
18022                transaction = apply_action.log_err().fuse() => transaction,
18023            };
18024            buffer
18025                .update(cx, |buffer, cx| {
18026                    // check if we need this
18027                    if let Some(transaction) = transaction
18028                        && !buffer.is_singleton()
18029                    {
18030                        buffer.push_transaction(&transaction.0, cx);
18031                    }
18032                    cx.notify();
18033                })
18034                .ok();
18035            Ok(())
18036        })
18037    }
18038
18039    pub fn restart_language_server(
18040        &mut self,
18041        _: &RestartLanguageServer,
18042        _: &mut Window,
18043        cx: &mut Context<Self>,
18044    ) {
18045        if let Some(project) = self.project.clone() {
18046            self.buffer.update(cx, |multi_buffer, cx| {
18047                project.update(cx, |project, cx| {
18048                    project.restart_language_servers_for_buffers(
18049                        multi_buffer.all_buffers().into_iter().collect(),
18050                        HashSet::default(),
18051                        cx,
18052                    );
18053                });
18054            })
18055        }
18056    }
18057
18058    pub fn stop_language_server(
18059        &mut self,
18060        _: &StopLanguageServer,
18061        _: &mut Window,
18062        cx: &mut Context<Self>,
18063    ) {
18064        if let Some(project) = self.project.clone() {
18065            self.buffer.update(cx, |multi_buffer, cx| {
18066                project.update(cx, |project, cx| {
18067                    project.stop_language_servers_for_buffers(
18068                        multi_buffer.all_buffers().into_iter().collect(),
18069                        HashSet::default(),
18070                        cx,
18071                    );
18072                });
18073            });
18074            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18075        }
18076    }
18077
18078    fn cancel_language_server_work(
18079        workspace: &mut Workspace,
18080        _: &actions::CancelLanguageServerWork,
18081        _: &mut Window,
18082        cx: &mut Context<Workspace>,
18083    ) {
18084        let project = workspace.project();
18085        let buffers = workspace
18086            .active_item(cx)
18087            .and_then(|item| item.act_as::<Editor>(cx))
18088            .map_or(HashSet::default(), |editor| {
18089                editor.read(cx).buffer.read(cx).all_buffers()
18090            });
18091        project.update(cx, |project, cx| {
18092            project.cancel_language_server_work_for_buffers(buffers, cx);
18093        });
18094    }
18095
18096    fn show_character_palette(
18097        &mut self,
18098        _: &ShowCharacterPalette,
18099        window: &mut Window,
18100        _: &mut Context<Self>,
18101    ) {
18102        window.show_character_palette();
18103    }
18104
18105    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18106        if !self.diagnostics_enabled() {
18107            return;
18108        }
18109
18110        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18111            let buffer = self.buffer.read(cx).snapshot(cx);
18112            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18113            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18114            let is_valid = buffer
18115                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18116                .any(|entry| {
18117                    entry.diagnostic.is_primary
18118                        && !entry.range.is_empty()
18119                        && entry.range.start == primary_range_start
18120                        && entry.diagnostic.message == active_diagnostics.active_message
18121                });
18122
18123            if !is_valid {
18124                self.dismiss_diagnostics(cx);
18125            }
18126        }
18127    }
18128
18129    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18130        match &self.active_diagnostics {
18131            ActiveDiagnostic::Group(group) => Some(group),
18132            _ => None,
18133        }
18134    }
18135
18136    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18137        if !self.diagnostics_enabled() {
18138            return;
18139        }
18140        self.dismiss_diagnostics(cx);
18141        self.active_diagnostics = ActiveDiagnostic::All;
18142    }
18143
18144    fn activate_diagnostics(
18145        &mut self,
18146        buffer_id: BufferId,
18147        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18148        window: &mut Window,
18149        cx: &mut Context<Self>,
18150    ) {
18151        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18152            return;
18153        }
18154        self.dismiss_diagnostics(cx);
18155        let snapshot = self.snapshot(window, cx);
18156        let buffer = self.buffer.read(cx).snapshot(cx);
18157        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18158            return;
18159        };
18160
18161        let diagnostic_group = buffer
18162            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18163            .collect::<Vec<_>>();
18164
18165        let language_registry = self
18166            .project()
18167            .map(|project| project.read(cx).languages().clone());
18168
18169        let blocks = renderer.render_group(
18170            diagnostic_group,
18171            buffer_id,
18172            snapshot,
18173            cx.weak_entity(),
18174            language_registry,
18175            cx,
18176        );
18177
18178        let blocks = self.display_map.update(cx, |display_map, cx| {
18179            display_map.insert_blocks(blocks, cx).into_iter().collect()
18180        });
18181        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18182            active_range: buffer.anchor_before(diagnostic.range.start)
18183                ..buffer.anchor_after(diagnostic.range.end),
18184            active_message: diagnostic.diagnostic.message.clone(),
18185            group_id: diagnostic.diagnostic.group_id,
18186            blocks,
18187        });
18188        cx.notify();
18189    }
18190
18191    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18192        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18193            return;
18194        };
18195
18196        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18197        if let ActiveDiagnostic::Group(group) = prev {
18198            self.display_map.update(cx, |display_map, cx| {
18199                display_map.remove_blocks(group.blocks, cx);
18200            });
18201            cx.notify();
18202        }
18203    }
18204
18205    /// Disable inline diagnostics rendering for this editor.
18206    pub fn disable_inline_diagnostics(&mut self) {
18207        self.inline_diagnostics_enabled = false;
18208        self.inline_diagnostics_update = Task::ready(());
18209        self.inline_diagnostics.clear();
18210    }
18211
18212    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18213        self.diagnostics_enabled = false;
18214        self.dismiss_diagnostics(cx);
18215        self.inline_diagnostics_update = Task::ready(());
18216        self.inline_diagnostics.clear();
18217    }
18218
18219    pub fn disable_word_completions(&mut self) {
18220        self.word_completions_enabled = false;
18221    }
18222
18223    pub fn diagnostics_enabled(&self) -> bool {
18224        self.diagnostics_enabled && self.mode.is_full()
18225    }
18226
18227    pub fn inline_diagnostics_enabled(&self) -> bool {
18228        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18229    }
18230
18231    pub fn show_inline_diagnostics(&self) -> bool {
18232        self.show_inline_diagnostics
18233    }
18234
18235    pub fn toggle_inline_diagnostics(
18236        &mut self,
18237        _: &ToggleInlineDiagnostics,
18238        window: &mut Window,
18239        cx: &mut Context<Editor>,
18240    ) {
18241        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18242        self.refresh_inline_diagnostics(false, window, cx);
18243    }
18244
18245    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18246        self.diagnostics_max_severity = severity;
18247        self.display_map.update(cx, |display_map, _| {
18248            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18249        });
18250    }
18251
18252    pub fn toggle_diagnostics(
18253        &mut self,
18254        _: &ToggleDiagnostics,
18255        window: &mut Window,
18256        cx: &mut Context<Editor>,
18257    ) {
18258        if !self.diagnostics_enabled() {
18259            return;
18260        }
18261
18262        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18263            EditorSettings::get_global(cx)
18264                .diagnostics_max_severity
18265                .filter(|severity| severity != &DiagnosticSeverity::Off)
18266                .unwrap_or(DiagnosticSeverity::Hint)
18267        } else {
18268            DiagnosticSeverity::Off
18269        };
18270        self.set_max_diagnostics_severity(new_severity, cx);
18271        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18272            self.active_diagnostics = ActiveDiagnostic::None;
18273            self.inline_diagnostics_update = Task::ready(());
18274            self.inline_diagnostics.clear();
18275        } else {
18276            self.refresh_inline_diagnostics(false, window, cx);
18277        }
18278
18279        cx.notify();
18280    }
18281
18282    pub fn toggle_minimap(
18283        &mut self,
18284        _: &ToggleMinimap,
18285        window: &mut Window,
18286        cx: &mut Context<Editor>,
18287    ) {
18288        if self.supports_minimap(cx) {
18289            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18290        }
18291    }
18292
18293    fn refresh_inline_diagnostics(
18294        &mut self,
18295        debounce: bool,
18296        window: &mut Window,
18297        cx: &mut Context<Self>,
18298    ) {
18299        let max_severity = ProjectSettings::get_global(cx)
18300            .diagnostics
18301            .inline
18302            .max_severity
18303            .unwrap_or(self.diagnostics_max_severity);
18304
18305        if !self.inline_diagnostics_enabled()
18306            || !self.diagnostics_enabled()
18307            || !self.show_inline_diagnostics
18308            || max_severity == DiagnosticSeverity::Off
18309        {
18310            self.inline_diagnostics_update = Task::ready(());
18311            self.inline_diagnostics.clear();
18312            return;
18313        }
18314
18315        let debounce_ms = ProjectSettings::get_global(cx)
18316            .diagnostics
18317            .inline
18318            .update_debounce_ms;
18319        let debounce = if debounce && debounce_ms > 0 {
18320            Some(Duration::from_millis(debounce_ms))
18321        } else {
18322            None
18323        };
18324        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18325            if let Some(debounce) = debounce {
18326                cx.background_executor().timer(debounce).await;
18327            }
18328            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18329                editor
18330                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18331                    .ok()
18332            }) else {
18333                return;
18334            };
18335
18336            let new_inline_diagnostics = cx
18337                .background_spawn(async move {
18338                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18339                    for diagnostic_entry in
18340                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18341                    {
18342                        let message = diagnostic_entry
18343                            .diagnostic
18344                            .message
18345                            .split_once('\n')
18346                            .map(|(line, _)| line)
18347                            .map(SharedString::new)
18348                            .unwrap_or_else(|| {
18349                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18350                            });
18351                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18352                        let (Ok(i) | Err(i)) = inline_diagnostics
18353                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18354                        inline_diagnostics.insert(
18355                            i,
18356                            (
18357                                start_anchor,
18358                                InlineDiagnostic {
18359                                    message,
18360                                    group_id: diagnostic_entry.diagnostic.group_id,
18361                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18362                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18363                                    severity: diagnostic_entry.diagnostic.severity,
18364                                },
18365                            ),
18366                        );
18367                    }
18368                    inline_diagnostics
18369                })
18370                .await;
18371
18372            editor
18373                .update(cx, |editor, cx| {
18374                    editor.inline_diagnostics = new_inline_diagnostics;
18375                    cx.notify();
18376                })
18377                .ok();
18378        });
18379    }
18380
18381    fn pull_diagnostics(
18382        &mut self,
18383        buffer_id: Option<BufferId>,
18384        window: &Window,
18385        cx: &mut Context<Self>,
18386    ) -> Option<()> {
18387        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18388            return None;
18389        }
18390        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18391            .diagnostics
18392            .lsp_pull_diagnostics;
18393        if !pull_diagnostics_settings.enabled {
18394            return None;
18395        }
18396        let project = self.project()?.downgrade();
18397        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18398        let mut buffers = self.buffer.read(cx).all_buffers();
18399        buffers.retain(|buffer| {
18400            let buffer_id_to_retain = buffer.read(cx).remote_id();
18401            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18402                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18403        });
18404        if buffers.is_empty() {
18405            self.pull_diagnostics_task = Task::ready(());
18406            return None;
18407        }
18408
18409        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18410            cx.background_executor().timer(debounce).await;
18411
18412            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18413                buffers
18414                    .into_iter()
18415                    .filter_map(|buffer| {
18416                        project
18417                            .update(cx, |project, cx| {
18418                                project.lsp_store().update(cx, |lsp_store, cx| {
18419                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18420                                })
18421                            })
18422                            .ok()
18423                    })
18424                    .collect::<FuturesUnordered<_>>()
18425            }) else {
18426                return;
18427            };
18428
18429            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18430                match pull_task {
18431                    Ok(()) => {
18432                        if editor
18433                            .update_in(cx, |editor, window, cx| {
18434                                editor.update_diagnostics_state(window, cx);
18435                            })
18436                            .is_err()
18437                        {
18438                            return;
18439                        }
18440                    }
18441                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18442                }
18443            }
18444        });
18445
18446        Some(())
18447    }
18448
18449    pub fn set_selections_from_remote(
18450        &mut self,
18451        selections: Vec<Selection<Anchor>>,
18452        pending_selection: Option<Selection<Anchor>>,
18453        window: &mut Window,
18454        cx: &mut Context<Self>,
18455    ) {
18456        let old_cursor_position = self.selections.newest_anchor().head();
18457        self.selections
18458            .change_with(&self.display_snapshot(cx), |s| {
18459                s.select_anchors(selections);
18460                if let Some(pending_selection) = pending_selection {
18461                    s.set_pending(pending_selection, SelectMode::Character);
18462                } else {
18463                    s.clear_pending();
18464                }
18465            });
18466        self.selections_did_change(
18467            false,
18468            &old_cursor_position,
18469            SelectionEffects::default(),
18470            window,
18471            cx,
18472        );
18473    }
18474
18475    pub fn transact(
18476        &mut self,
18477        window: &mut Window,
18478        cx: &mut Context<Self>,
18479        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18480    ) -> Option<TransactionId> {
18481        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18482            this.start_transaction_at(Instant::now(), window, cx);
18483            update(this, window, cx);
18484            this.end_transaction_at(Instant::now(), cx)
18485        })
18486    }
18487
18488    pub fn start_transaction_at(
18489        &mut self,
18490        now: Instant,
18491        window: &mut Window,
18492        cx: &mut Context<Self>,
18493    ) -> Option<TransactionId> {
18494        self.end_selection(window, cx);
18495        if let Some(tx_id) = self
18496            .buffer
18497            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18498        {
18499            self.selection_history
18500                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18501            cx.emit(EditorEvent::TransactionBegun {
18502                transaction_id: tx_id,
18503            });
18504            Some(tx_id)
18505        } else {
18506            None
18507        }
18508    }
18509
18510    pub fn end_transaction_at(
18511        &mut self,
18512        now: Instant,
18513        cx: &mut Context<Self>,
18514    ) -> Option<TransactionId> {
18515        if let Some(transaction_id) = self
18516            .buffer
18517            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18518        {
18519            if let Some((_, end_selections)) =
18520                self.selection_history.transaction_mut(transaction_id)
18521            {
18522                *end_selections = Some(self.selections.disjoint_anchors_arc());
18523            } else {
18524                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18525            }
18526
18527            cx.emit(EditorEvent::Edited { transaction_id });
18528            Some(transaction_id)
18529        } else {
18530            None
18531        }
18532    }
18533
18534    pub fn modify_transaction_selection_history(
18535        &mut self,
18536        transaction_id: TransactionId,
18537        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18538    ) -> bool {
18539        self.selection_history
18540            .transaction_mut(transaction_id)
18541            .map(modify)
18542            .is_some()
18543    }
18544
18545    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18546        if self.selection_mark_mode {
18547            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18548                s.move_with(|_, sel| {
18549                    sel.collapse_to(sel.head(), SelectionGoal::None);
18550                });
18551            })
18552        }
18553        self.selection_mark_mode = true;
18554        cx.notify();
18555    }
18556
18557    pub fn swap_selection_ends(
18558        &mut self,
18559        _: &actions::SwapSelectionEnds,
18560        window: &mut Window,
18561        cx: &mut Context<Self>,
18562    ) {
18563        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18564            s.move_with(|_, sel| {
18565                if sel.start != sel.end {
18566                    sel.reversed = !sel.reversed
18567                }
18568            });
18569        });
18570        self.request_autoscroll(Autoscroll::newest(), cx);
18571        cx.notify();
18572    }
18573
18574    pub fn toggle_focus(
18575        workspace: &mut Workspace,
18576        _: &actions::ToggleFocus,
18577        window: &mut Window,
18578        cx: &mut Context<Workspace>,
18579    ) {
18580        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18581            return;
18582        };
18583        workspace.activate_item(&item, true, true, window, cx);
18584    }
18585
18586    pub fn toggle_fold(
18587        &mut self,
18588        _: &actions::ToggleFold,
18589        window: &mut Window,
18590        cx: &mut Context<Self>,
18591    ) {
18592        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18593            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18594            let selection = self.selections.newest::<Point>(&display_map);
18595
18596            let range = if selection.is_empty() {
18597                let point = selection.head().to_display_point(&display_map);
18598                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18599                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18600                    .to_point(&display_map);
18601                start..end
18602            } else {
18603                selection.range()
18604            };
18605            if display_map.folds_in_range(range).next().is_some() {
18606                self.unfold_lines(&Default::default(), window, cx)
18607            } else {
18608                self.fold(&Default::default(), window, cx)
18609            }
18610        } else {
18611            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18612            let buffer_ids: HashSet<_> = self
18613                .selections
18614                .disjoint_anchor_ranges()
18615                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18616                .collect();
18617
18618            let should_unfold = buffer_ids
18619                .iter()
18620                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18621
18622            for buffer_id in buffer_ids {
18623                if should_unfold {
18624                    self.unfold_buffer(buffer_id, cx);
18625                } else {
18626                    self.fold_buffer(buffer_id, cx);
18627                }
18628            }
18629        }
18630    }
18631
18632    pub fn toggle_fold_recursive(
18633        &mut self,
18634        _: &actions::ToggleFoldRecursive,
18635        window: &mut Window,
18636        cx: &mut Context<Self>,
18637    ) {
18638        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18639
18640        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18641        let range = if selection.is_empty() {
18642            let point = selection.head().to_display_point(&display_map);
18643            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18644            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18645                .to_point(&display_map);
18646            start..end
18647        } else {
18648            selection.range()
18649        };
18650        if display_map.folds_in_range(range).next().is_some() {
18651            self.unfold_recursive(&Default::default(), window, cx)
18652        } else {
18653            self.fold_recursive(&Default::default(), window, cx)
18654        }
18655    }
18656
18657    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18658        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18659            let mut to_fold = Vec::new();
18660            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18661            let selections = self.selections.all_adjusted(&display_map);
18662
18663            for selection in selections {
18664                let range = selection.range().sorted();
18665                let buffer_start_row = range.start.row;
18666
18667                if range.start.row != range.end.row {
18668                    let mut found = false;
18669                    let mut row = range.start.row;
18670                    while row <= range.end.row {
18671                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18672                        {
18673                            found = true;
18674                            row = crease.range().end.row + 1;
18675                            to_fold.push(crease);
18676                        } else {
18677                            row += 1
18678                        }
18679                    }
18680                    if found {
18681                        continue;
18682                    }
18683                }
18684
18685                for row in (0..=range.start.row).rev() {
18686                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18687                        && crease.range().end.row >= buffer_start_row
18688                    {
18689                        to_fold.push(crease);
18690                        if row <= range.start.row {
18691                            break;
18692                        }
18693                    }
18694                }
18695            }
18696
18697            self.fold_creases(to_fold, true, window, cx);
18698        } else {
18699            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18700            let buffer_ids = self
18701                .selections
18702                .disjoint_anchor_ranges()
18703                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18704                .collect::<HashSet<_>>();
18705            for buffer_id in buffer_ids {
18706                self.fold_buffer(buffer_id, cx);
18707            }
18708        }
18709    }
18710
18711    pub fn toggle_fold_all(
18712        &mut self,
18713        _: &actions::ToggleFoldAll,
18714        window: &mut Window,
18715        cx: &mut Context<Self>,
18716    ) {
18717        if self.buffer.read(cx).is_singleton() {
18718            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18719            let has_folds = display_map
18720                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
18721                .next()
18722                .is_some();
18723
18724            if has_folds {
18725                self.unfold_all(&actions::UnfoldAll, window, cx);
18726            } else {
18727                self.fold_all(&actions::FoldAll, window, cx);
18728            }
18729        } else {
18730            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18731            let should_unfold = buffer_ids
18732                .iter()
18733                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18734
18735            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18736                editor
18737                    .update_in(cx, |editor, _, cx| {
18738                        for buffer_id in buffer_ids {
18739                            if should_unfold {
18740                                editor.unfold_buffer(buffer_id, cx);
18741                            } else {
18742                                editor.fold_buffer(buffer_id, cx);
18743                            }
18744                        }
18745                    })
18746                    .ok();
18747            });
18748        }
18749    }
18750
18751    fn fold_at_level(
18752        &mut self,
18753        fold_at: &FoldAtLevel,
18754        window: &mut Window,
18755        cx: &mut Context<Self>,
18756    ) {
18757        if !self.buffer.read(cx).is_singleton() {
18758            return;
18759        }
18760
18761        let fold_at_level = fold_at.0;
18762        let snapshot = self.buffer.read(cx).snapshot(cx);
18763        let mut to_fold = Vec::new();
18764        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18765
18766        let row_ranges_to_keep: Vec<Range<u32>> = self
18767            .selections
18768            .all::<Point>(&self.display_snapshot(cx))
18769            .into_iter()
18770            .map(|sel| sel.start.row..sel.end.row)
18771            .collect();
18772
18773        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18774            while start_row < end_row {
18775                match self
18776                    .snapshot(window, cx)
18777                    .crease_for_buffer_row(MultiBufferRow(start_row))
18778                {
18779                    Some(crease) => {
18780                        let nested_start_row = crease.range().start.row + 1;
18781                        let nested_end_row = crease.range().end.row;
18782
18783                        if current_level < fold_at_level {
18784                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18785                        } else if current_level == fold_at_level {
18786                            // Fold iff there is no selection completely contained within the fold region
18787                            if !row_ranges_to_keep.iter().any(|selection| {
18788                                selection.end >= nested_start_row
18789                                    && selection.start <= nested_end_row
18790                            }) {
18791                                to_fold.push(crease);
18792                            }
18793                        }
18794
18795                        start_row = nested_end_row + 1;
18796                    }
18797                    None => start_row += 1,
18798                }
18799            }
18800        }
18801
18802        self.fold_creases(to_fold, true, window, cx);
18803    }
18804
18805    pub fn fold_at_level_1(
18806        &mut self,
18807        _: &actions::FoldAtLevel1,
18808        window: &mut Window,
18809        cx: &mut Context<Self>,
18810    ) {
18811        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18812    }
18813
18814    pub fn fold_at_level_2(
18815        &mut self,
18816        _: &actions::FoldAtLevel2,
18817        window: &mut Window,
18818        cx: &mut Context<Self>,
18819    ) {
18820        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18821    }
18822
18823    pub fn fold_at_level_3(
18824        &mut self,
18825        _: &actions::FoldAtLevel3,
18826        window: &mut Window,
18827        cx: &mut Context<Self>,
18828    ) {
18829        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18830    }
18831
18832    pub fn fold_at_level_4(
18833        &mut self,
18834        _: &actions::FoldAtLevel4,
18835        window: &mut Window,
18836        cx: &mut Context<Self>,
18837    ) {
18838        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18839    }
18840
18841    pub fn fold_at_level_5(
18842        &mut self,
18843        _: &actions::FoldAtLevel5,
18844        window: &mut Window,
18845        cx: &mut Context<Self>,
18846    ) {
18847        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18848    }
18849
18850    pub fn fold_at_level_6(
18851        &mut self,
18852        _: &actions::FoldAtLevel6,
18853        window: &mut Window,
18854        cx: &mut Context<Self>,
18855    ) {
18856        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18857    }
18858
18859    pub fn fold_at_level_7(
18860        &mut self,
18861        _: &actions::FoldAtLevel7,
18862        window: &mut Window,
18863        cx: &mut Context<Self>,
18864    ) {
18865        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18866    }
18867
18868    pub fn fold_at_level_8(
18869        &mut self,
18870        _: &actions::FoldAtLevel8,
18871        window: &mut Window,
18872        cx: &mut Context<Self>,
18873    ) {
18874        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18875    }
18876
18877    pub fn fold_at_level_9(
18878        &mut self,
18879        _: &actions::FoldAtLevel9,
18880        window: &mut Window,
18881        cx: &mut Context<Self>,
18882    ) {
18883        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18884    }
18885
18886    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18887        if self.buffer.read(cx).is_singleton() {
18888            let mut fold_ranges = Vec::new();
18889            let snapshot = self.buffer.read(cx).snapshot(cx);
18890
18891            for row in 0..snapshot.max_row().0 {
18892                if let Some(foldable_range) = self
18893                    .snapshot(window, cx)
18894                    .crease_for_buffer_row(MultiBufferRow(row))
18895                {
18896                    fold_ranges.push(foldable_range);
18897                }
18898            }
18899
18900            self.fold_creases(fold_ranges, true, window, cx);
18901        } else {
18902            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18903                editor
18904                    .update_in(cx, |editor, _, cx| {
18905                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18906                            editor.fold_buffer(buffer_id, cx);
18907                        }
18908                    })
18909                    .ok();
18910            });
18911        }
18912    }
18913
18914    pub fn fold_function_bodies(
18915        &mut self,
18916        _: &actions::FoldFunctionBodies,
18917        window: &mut Window,
18918        cx: &mut Context<Self>,
18919    ) {
18920        let snapshot = self.buffer.read(cx).snapshot(cx);
18921
18922        let ranges = snapshot
18923            .text_object_ranges(
18924                MultiBufferOffset(0)..snapshot.len(),
18925                TreeSitterOptions::default(),
18926            )
18927            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18928            .collect::<Vec<_>>();
18929
18930        let creases = ranges
18931            .into_iter()
18932            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18933            .collect();
18934
18935        self.fold_creases(creases, true, window, cx);
18936    }
18937
18938    pub fn fold_recursive(
18939        &mut self,
18940        _: &actions::FoldRecursive,
18941        window: &mut Window,
18942        cx: &mut Context<Self>,
18943    ) {
18944        let mut to_fold = Vec::new();
18945        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18946        let selections = self.selections.all_adjusted(&display_map);
18947
18948        for selection in selections {
18949            let range = selection.range().sorted();
18950            let buffer_start_row = range.start.row;
18951
18952            if range.start.row != range.end.row {
18953                let mut found = false;
18954                for row in range.start.row..=range.end.row {
18955                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18956                        found = true;
18957                        to_fold.push(crease);
18958                    }
18959                }
18960                if found {
18961                    continue;
18962                }
18963            }
18964
18965            for row in (0..=range.start.row).rev() {
18966                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18967                    if crease.range().end.row >= buffer_start_row {
18968                        to_fold.push(crease);
18969                    } else {
18970                        break;
18971                    }
18972                }
18973            }
18974        }
18975
18976        self.fold_creases(to_fold, true, window, cx);
18977    }
18978
18979    pub fn fold_at(
18980        &mut self,
18981        buffer_row: MultiBufferRow,
18982        window: &mut Window,
18983        cx: &mut Context<Self>,
18984    ) {
18985        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18986
18987        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18988            let autoscroll = self
18989                .selections
18990                .all::<Point>(&display_map)
18991                .iter()
18992                .any(|selection| crease.range().overlaps(&selection.range()));
18993
18994            self.fold_creases(vec![crease], autoscroll, window, cx);
18995        }
18996    }
18997
18998    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18999        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19000            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19001            let buffer = display_map.buffer_snapshot();
19002            let selections = self.selections.all::<Point>(&display_map);
19003            let ranges = selections
19004                .iter()
19005                .map(|s| {
19006                    let range = s.display_range(&display_map).sorted();
19007                    let mut start = range.start.to_point(&display_map);
19008                    let mut end = range.end.to_point(&display_map);
19009                    start.column = 0;
19010                    end.column = buffer.line_len(MultiBufferRow(end.row));
19011                    start..end
19012                })
19013                .collect::<Vec<_>>();
19014
19015            self.unfold_ranges(&ranges, true, true, cx);
19016        } else {
19017            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19018            let buffer_ids = self
19019                .selections
19020                .disjoint_anchor_ranges()
19021                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19022                .collect::<HashSet<_>>();
19023            for buffer_id in buffer_ids {
19024                self.unfold_buffer(buffer_id, cx);
19025            }
19026        }
19027    }
19028
19029    pub fn unfold_recursive(
19030        &mut self,
19031        _: &UnfoldRecursive,
19032        _window: &mut Window,
19033        cx: &mut Context<Self>,
19034    ) {
19035        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19036        let selections = self.selections.all::<Point>(&display_map);
19037        let ranges = selections
19038            .iter()
19039            .map(|s| {
19040                let mut range = s.display_range(&display_map).sorted();
19041                *range.start.column_mut() = 0;
19042                *range.end.column_mut() = display_map.line_len(range.end.row());
19043                let start = range.start.to_point(&display_map);
19044                let end = range.end.to_point(&display_map);
19045                start..end
19046            })
19047            .collect::<Vec<_>>();
19048
19049        self.unfold_ranges(&ranges, true, true, cx);
19050    }
19051
19052    pub fn unfold_at(
19053        &mut self,
19054        buffer_row: MultiBufferRow,
19055        _window: &mut Window,
19056        cx: &mut Context<Self>,
19057    ) {
19058        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19059
19060        let intersection_range = Point::new(buffer_row.0, 0)
19061            ..Point::new(
19062                buffer_row.0,
19063                display_map.buffer_snapshot().line_len(buffer_row),
19064            );
19065
19066        let autoscroll = self
19067            .selections
19068            .all::<Point>(&display_map)
19069            .iter()
19070            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19071
19072        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19073    }
19074
19075    pub fn unfold_all(
19076        &mut self,
19077        _: &actions::UnfoldAll,
19078        _window: &mut Window,
19079        cx: &mut Context<Self>,
19080    ) {
19081        if self.buffer.read(cx).is_singleton() {
19082            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19083            self.unfold_ranges(
19084                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19085                true,
19086                true,
19087                cx,
19088            );
19089        } else {
19090            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19091                editor
19092                    .update(cx, |editor, cx| {
19093                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19094                            editor.unfold_buffer(buffer_id, cx);
19095                        }
19096                    })
19097                    .ok();
19098            });
19099        }
19100    }
19101
19102    pub fn fold_selected_ranges(
19103        &mut self,
19104        _: &FoldSelectedRanges,
19105        window: &mut Window,
19106        cx: &mut Context<Self>,
19107    ) {
19108        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19109        let selections = self.selections.all_adjusted(&display_map);
19110        let ranges = selections
19111            .into_iter()
19112            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19113            .collect::<Vec<_>>();
19114        self.fold_creases(ranges, true, window, cx);
19115    }
19116
19117    pub fn fold_ranges<T: ToOffset + Clone>(
19118        &mut self,
19119        ranges: Vec<Range<T>>,
19120        auto_scroll: bool,
19121        window: &mut Window,
19122        cx: &mut Context<Self>,
19123    ) {
19124        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19125        let ranges = ranges
19126            .into_iter()
19127            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19128            .collect::<Vec<_>>();
19129        self.fold_creases(ranges, auto_scroll, window, cx);
19130    }
19131
19132    pub fn fold_creases<T: ToOffset + Clone>(
19133        &mut self,
19134        creases: Vec<Crease<T>>,
19135        auto_scroll: bool,
19136        _window: &mut Window,
19137        cx: &mut Context<Self>,
19138    ) {
19139        if creases.is_empty() {
19140            return;
19141        }
19142
19143        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19144
19145        if auto_scroll {
19146            self.request_autoscroll(Autoscroll::fit(), cx);
19147        }
19148
19149        cx.notify();
19150
19151        self.scrollbar_marker_state.dirty = true;
19152        self.folds_did_change(cx);
19153    }
19154
19155    /// Removes any folds whose ranges intersect any of the given ranges.
19156    pub fn unfold_ranges<T: ToOffset + Clone>(
19157        &mut self,
19158        ranges: &[Range<T>],
19159        inclusive: bool,
19160        auto_scroll: bool,
19161        cx: &mut Context<Self>,
19162    ) {
19163        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19164            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19165        });
19166        self.folds_did_change(cx);
19167    }
19168
19169    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19170        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19171            return;
19172        }
19173
19174        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19175        self.display_map.update(cx, |display_map, cx| {
19176            display_map.fold_buffers([buffer_id], cx)
19177        });
19178
19179        let snapshot = self.display_snapshot(cx);
19180        self.selections.change_with(&snapshot, |selections| {
19181            selections.remove_selections_from_buffer(buffer_id);
19182        });
19183
19184        cx.emit(EditorEvent::BufferFoldToggled {
19185            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19186            folded: true,
19187        });
19188        cx.notify();
19189    }
19190
19191    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19192        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19193            return;
19194        }
19195        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19196        self.display_map.update(cx, |display_map, cx| {
19197            display_map.unfold_buffers([buffer_id], cx);
19198        });
19199        cx.emit(EditorEvent::BufferFoldToggled {
19200            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19201            folded: false,
19202        });
19203        cx.notify();
19204    }
19205
19206    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19207        self.display_map.read(cx).is_buffer_folded(buffer)
19208    }
19209
19210    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19211        self.display_map.read(cx).folded_buffers()
19212    }
19213
19214    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19215        self.display_map.update(cx, |display_map, cx| {
19216            display_map.disable_header_for_buffer(buffer_id, cx);
19217        });
19218        cx.notify();
19219    }
19220
19221    /// Removes any folds with the given ranges.
19222    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19223        &mut self,
19224        ranges: &[Range<T>],
19225        type_id: TypeId,
19226        auto_scroll: bool,
19227        cx: &mut Context<Self>,
19228    ) {
19229        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19230            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19231        });
19232        self.folds_did_change(cx);
19233    }
19234
19235    fn remove_folds_with<T: ToOffset + Clone>(
19236        &mut self,
19237        ranges: &[Range<T>],
19238        auto_scroll: bool,
19239        cx: &mut Context<Self>,
19240        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19241    ) {
19242        if ranges.is_empty() {
19243            return;
19244        }
19245
19246        let mut buffers_affected = HashSet::default();
19247        let multi_buffer = self.buffer().read(cx);
19248        for range in ranges {
19249            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19250                buffers_affected.insert(buffer.read(cx).remote_id());
19251            };
19252        }
19253
19254        self.display_map.update(cx, update);
19255
19256        if auto_scroll {
19257            self.request_autoscroll(Autoscroll::fit(), cx);
19258        }
19259
19260        cx.notify();
19261        self.scrollbar_marker_state.dirty = true;
19262        self.active_indent_guides_state.dirty = true;
19263    }
19264
19265    pub fn update_renderer_widths(
19266        &mut self,
19267        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19268        cx: &mut Context<Self>,
19269    ) -> bool {
19270        self.display_map
19271            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19272    }
19273
19274    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19275        self.display_map.read(cx).fold_placeholder.clone()
19276    }
19277
19278    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19279        self.buffer.update(cx, |buffer, cx| {
19280            buffer.set_all_diff_hunks_expanded(cx);
19281        });
19282    }
19283
19284    pub fn expand_all_diff_hunks(
19285        &mut self,
19286        _: &ExpandAllDiffHunks,
19287        _window: &mut Window,
19288        cx: &mut Context<Self>,
19289    ) {
19290        self.buffer.update(cx, |buffer, cx| {
19291            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19292        });
19293    }
19294
19295    pub fn collapse_all_diff_hunks(
19296        &mut self,
19297        _: &CollapseAllDiffHunks,
19298        _window: &mut Window,
19299        cx: &mut Context<Self>,
19300    ) {
19301        self.buffer.update(cx, |buffer, cx| {
19302            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19303        });
19304    }
19305
19306    pub fn toggle_selected_diff_hunks(
19307        &mut self,
19308        _: &ToggleSelectedDiffHunks,
19309        _window: &mut Window,
19310        cx: &mut Context<Self>,
19311    ) {
19312        let ranges: Vec<_> = self
19313            .selections
19314            .disjoint_anchors()
19315            .iter()
19316            .map(|s| s.range())
19317            .collect();
19318        self.toggle_diff_hunks_in_ranges(ranges, cx);
19319    }
19320
19321    pub fn diff_hunks_in_ranges<'a>(
19322        &'a self,
19323        ranges: &'a [Range<Anchor>],
19324        buffer: &'a MultiBufferSnapshot,
19325    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19326        ranges.iter().flat_map(move |range| {
19327            let end_excerpt_id = range.end.excerpt_id;
19328            let range = range.to_point(buffer);
19329            let mut peek_end = range.end;
19330            if range.end.row < buffer.max_row().0 {
19331                peek_end = Point::new(range.end.row + 1, 0);
19332            }
19333            buffer
19334                .diff_hunks_in_range(range.start..peek_end)
19335                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19336        })
19337    }
19338
19339    pub fn has_stageable_diff_hunks_in_ranges(
19340        &self,
19341        ranges: &[Range<Anchor>],
19342        snapshot: &MultiBufferSnapshot,
19343    ) -> bool {
19344        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19345        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19346    }
19347
19348    pub fn toggle_staged_selected_diff_hunks(
19349        &mut self,
19350        _: &::git::ToggleStaged,
19351        _: &mut Window,
19352        cx: &mut Context<Self>,
19353    ) {
19354        let snapshot = self.buffer.read(cx).snapshot(cx);
19355        let ranges: Vec<_> = self
19356            .selections
19357            .disjoint_anchors()
19358            .iter()
19359            .map(|s| s.range())
19360            .collect();
19361        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19362        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19363    }
19364
19365    pub fn set_render_diff_hunk_controls(
19366        &mut self,
19367        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19368        cx: &mut Context<Self>,
19369    ) {
19370        self.render_diff_hunk_controls = render_diff_hunk_controls;
19371        cx.notify();
19372    }
19373
19374    pub fn stage_and_next(
19375        &mut self,
19376        _: &::git::StageAndNext,
19377        window: &mut Window,
19378        cx: &mut Context<Self>,
19379    ) {
19380        self.do_stage_or_unstage_and_next(true, window, cx);
19381    }
19382
19383    pub fn unstage_and_next(
19384        &mut self,
19385        _: &::git::UnstageAndNext,
19386        window: &mut Window,
19387        cx: &mut Context<Self>,
19388    ) {
19389        self.do_stage_or_unstage_and_next(false, window, cx);
19390    }
19391
19392    pub fn stage_or_unstage_diff_hunks(
19393        &mut self,
19394        stage: bool,
19395        ranges: Vec<Range<Anchor>>,
19396        cx: &mut Context<Self>,
19397    ) {
19398        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19399        cx.spawn(async move |this, cx| {
19400            task.await?;
19401            this.update(cx, |this, cx| {
19402                let snapshot = this.buffer.read(cx).snapshot(cx);
19403                let chunk_by = this
19404                    .diff_hunks_in_ranges(&ranges, &snapshot)
19405                    .chunk_by(|hunk| hunk.buffer_id);
19406                for (buffer_id, hunks) in &chunk_by {
19407                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19408                }
19409            })
19410        })
19411        .detach_and_log_err(cx);
19412    }
19413
19414    fn save_buffers_for_ranges_if_needed(
19415        &mut self,
19416        ranges: &[Range<Anchor>],
19417        cx: &mut Context<Editor>,
19418    ) -> Task<Result<()>> {
19419        let multibuffer = self.buffer.read(cx);
19420        let snapshot = multibuffer.read(cx);
19421        let buffer_ids: HashSet<_> = ranges
19422            .iter()
19423            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19424            .collect();
19425        drop(snapshot);
19426
19427        let mut buffers = HashSet::default();
19428        for buffer_id in buffer_ids {
19429            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19430                let buffer = buffer_entity.read(cx);
19431                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19432                {
19433                    buffers.insert(buffer_entity);
19434                }
19435            }
19436        }
19437
19438        if let Some(project) = &self.project {
19439            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19440        } else {
19441            Task::ready(Ok(()))
19442        }
19443    }
19444
19445    fn do_stage_or_unstage_and_next(
19446        &mut self,
19447        stage: bool,
19448        window: &mut Window,
19449        cx: &mut Context<Self>,
19450    ) {
19451        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19452
19453        if ranges.iter().any(|range| range.start != range.end) {
19454            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19455            return;
19456        }
19457
19458        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19459        let snapshot = self.snapshot(window, cx);
19460        let position = self
19461            .selections
19462            .newest::<Point>(&snapshot.display_snapshot)
19463            .head();
19464        let mut row = snapshot
19465            .buffer_snapshot()
19466            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19467            .find(|hunk| hunk.row_range.start.0 > position.row)
19468            .map(|hunk| hunk.row_range.start);
19469
19470        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19471        // Outside of the project diff editor, wrap around to the beginning.
19472        if !all_diff_hunks_expanded {
19473            row = row.or_else(|| {
19474                snapshot
19475                    .buffer_snapshot()
19476                    .diff_hunks_in_range(Point::zero()..position)
19477                    .find(|hunk| hunk.row_range.end.0 < position.row)
19478                    .map(|hunk| hunk.row_range.start)
19479            });
19480        }
19481
19482        if let Some(row) = row {
19483            let destination = Point::new(row.0, 0);
19484            let autoscroll = Autoscroll::center();
19485
19486            self.unfold_ranges(&[destination..destination], false, false, cx);
19487            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19488                s.select_ranges([destination..destination]);
19489            });
19490        }
19491    }
19492
19493    fn do_stage_or_unstage(
19494        &self,
19495        stage: bool,
19496        buffer_id: BufferId,
19497        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19498        cx: &mut App,
19499    ) -> Option<()> {
19500        let project = self.project()?;
19501        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19502        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19503        let buffer_snapshot = buffer.read(cx).snapshot();
19504        let file_exists = buffer_snapshot
19505            .file()
19506            .is_some_and(|file| file.disk_state().exists());
19507        diff.update(cx, |diff, cx| {
19508            diff.stage_or_unstage_hunks(
19509                stage,
19510                &hunks
19511                    .map(|hunk| buffer_diff::DiffHunk {
19512                        buffer_range: hunk.buffer_range,
19513                        // We don't need to pass in word diffs here because they're only used for rendering and
19514                        // this function changes internal state
19515                        base_word_diffs: Vec::default(),
19516                        buffer_word_diffs: Vec::default(),
19517                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19518                            ..hunk.diff_base_byte_range.end.0,
19519                        secondary_status: hunk.secondary_status,
19520                        range: Point::zero()..Point::zero(), // unused
19521                    })
19522                    .collect::<Vec<_>>(),
19523                &buffer_snapshot,
19524                file_exists,
19525                cx,
19526            )
19527        });
19528        None
19529    }
19530
19531    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19532        let ranges: Vec<_> = self
19533            .selections
19534            .disjoint_anchors()
19535            .iter()
19536            .map(|s| s.range())
19537            .collect();
19538        self.buffer
19539            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19540    }
19541
19542    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19543        self.buffer.update(cx, |buffer, cx| {
19544            let ranges = vec![Anchor::min()..Anchor::max()];
19545            if !buffer.all_diff_hunks_expanded()
19546                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19547            {
19548                buffer.collapse_diff_hunks(ranges, cx);
19549                true
19550            } else {
19551                false
19552            }
19553        })
19554    }
19555
19556    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19557        if self.buffer.read(cx).all_diff_hunks_expanded() {
19558            return true;
19559        }
19560        let ranges = vec![Anchor::min()..Anchor::max()];
19561        self.buffer
19562            .read(cx)
19563            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19564    }
19565
19566    fn toggle_diff_hunks_in_ranges(
19567        &mut self,
19568        ranges: Vec<Range<Anchor>>,
19569        cx: &mut Context<Editor>,
19570    ) {
19571        self.buffer.update(cx, |buffer, cx| {
19572            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19573            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19574        })
19575    }
19576
19577    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19578        self.buffer.update(cx, |buffer, cx| {
19579            let snapshot = buffer.snapshot(cx);
19580            let excerpt_id = range.end.excerpt_id;
19581            let point_range = range.to_point(&snapshot);
19582            let expand = !buffer.single_hunk_is_expanded(range, cx);
19583            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19584        })
19585    }
19586
19587    pub(crate) fn apply_all_diff_hunks(
19588        &mut self,
19589        _: &ApplyAllDiffHunks,
19590        window: &mut Window,
19591        cx: &mut Context<Self>,
19592    ) {
19593        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19594
19595        let buffers = self.buffer.read(cx).all_buffers();
19596        for branch_buffer in buffers {
19597            branch_buffer.update(cx, |branch_buffer, cx| {
19598                branch_buffer.merge_into_base(Vec::new(), cx);
19599            });
19600        }
19601
19602        if let Some(project) = self.project.clone() {
19603            self.save(
19604                SaveOptions {
19605                    format: true,
19606                    autosave: false,
19607                },
19608                project,
19609                window,
19610                cx,
19611            )
19612            .detach_and_log_err(cx);
19613        }
19614    }
19615
19616    pub(crate) fn apply_selected_diff_hunks(
19617        &mut self,
19618        _: &ApplyDiffHunk,
19619        window: &mut Window,
19620        cx: &mut Context<Self>,
19621    ) {
19622        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19623        let snapshot = self.snapshot(window, cx);
19624        let hunks = snapshot.hunks_for_ranges(
19625            self.selections
19626                .all(&snapshot.display_snapshot)
19627                .into_iter()
19628                .map(|selection| selection.range()),
19629        );
19630        let mut ranges_by_buffer = HashMap::default();
19631        self.transact(window, cx, |editor, _window, cx| {
19632            for hunk in hunks {
19633                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19634                    ranges_by_buffer
19635                        .entry(buffer.clone())
19636                        .or_insert_with(Vec::new)
19637                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19638                }
19639            }
19640
19641            for (buffer, ranges) in ranges_by_buffer {
19642                buffer.update(cx, |buffer, cx| {
19643                    buffer.merge_into_base(ranges, cx);
19644                });
19645            }
19646        });
19647
19648        if let Some(project) = self.project.clone() {
19649            self.save(
19650                SaveOptions {
19651                    format: true,
19652                    autosave: false,
19653                },
19654                project,
19655                window,
19656                cx,
19657            )
19658            .detach_and_log_err(cx);
19659        }
19660    }
19661
19662    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19663        if hovered != self.gutter_hovered {
19664            self.gutter_hovered = hovered;
19665            cx.notify();
19666        }
19667    }
19668
19669    pub fn insert_blocks(
19670        &mut self,
19671        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19672        autoscroll: Option<Autoscroll>,
19673        cx: &mut Context<Self>,
19674    ) -> Vec<CustomBlockId> {
19675        let blocks = self
19676            .display_map
19677            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19678        if let Some(autoscroll) = autoscroll {
19679            self.request_autoscroll(autoscroll, cx);
19680        }
19681        cx.notify();
19682        blocks
19683    }
19684
19685    pub fn resize_blocks(
19686        &mut self,
19687        heights: HashMap<CustomBlockId, u32>,
19688        autoscroll: Option<Autoscroll>,
19689        cx: &mut Context<Self>,
19690    ) {
19691        self.display_map
19692            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19693        if let Some(autoscroll) = autoscroll {
19694            self.request_autoscroll(autoscroll, cx);
19695        }
19696        cx.notify();
19697    }
19698
19699    pub fn replace_blocks(
19700        &mut self,
19701        renderers: HashMap<CustomBlockId, RenderBlock>,
19702        autoscroll: Option<Autoscroll>,
19703        cx: &mut Context<Self>,
19704    ) {
19705        self.display_map
19706            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19707        if let Some(autoscroll) = autoscroll {
19708            self.request_autoscroll(autoscroll, cx);
19709        }
19710        cx.notify();
19711    }
19712
19713    pub fn remove_blocks(
19714        &mut self,
19715        block_ids: HashSet<CustomBlockId>,
19716        autoscroll: Option<Autoscroll>,
19717        cx: &mut Context<Self>,
19718    ) {
19719        self.display_map.update(cx, |display_map, cx| {
19720            display_map.remove_blocks(block_ids, cx)
19721        });
19722        if let Some(autoscroll) = autoscroll {
19723            self.request_autoscroll(autoscroll, cx);
19724        }
19725        cx.notify();
19726    }
19727
19728    pub fn row_for_block(
19729        &self,
19730        block_id: CustomBlockId,
19731        cx: &mut Context<Self>,
19732    ) -> Option<DisplayRow> {
19733        self.display_map
19734            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19735    }
19736
19737    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19738        self.focused_block = Some(focused_block);
19739    }
19740
19741    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19742        self.focused_block.take()
19743    }
19744
19745    pub fn insert_creases(
19746        &mut self,
19747        creases: impl IntoIterator<Item = Crease<Anchor>>,
19748        cx: &mut Context<Self>,
19749    ) -> Vec<CreaseId> {
19750        self.display_map
19751            .update(cx, |map, cx| map.insert_creases(creases, cx))
19752    }
19753
19754    pub fn remove_creases(
19755        &mut self,
19756        ids: impl IntoIterator<Item = CreaseId>,
19757        cx: &mut Context<Self>,
19758    ) -> Vec<(CreaseId, Range<Anchor>)> {
19759        self.display_map
19760            .update(cx, |map, cx| map.remove_creases(ids, cx))
19761    }
19762
19763    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19764        self.display_map
19765            .update(cx, |map, cx| map.snapshot(cx))
19766            .longest_row()
19767    }
19768
19769    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19770        self.display_map
19771            .update(cx, |map, cx| map.snapshot(cx))
19772            .max_point()
19773    }
19774
19775    pub fn text(&self, cx: &App) -> String {
19776        self.buffer.read(cx).read(cx).text()
19777    }
19778
19779    pub fn is_empty(&self, cx: &App) -> bool {
19780        self.buffer.read(cx).read(cx).is_empty()
19781    }
19782
19783    pub fn text_option(&self, cx: &App) -> Option<String> {
19784        let text = self.text(cx);
19785        let text = text.trim();
19786
19787        if text.is_empty() {
19788            return None;
19789        }
19790
19791        Some(text.to_string())
19792    }
19793
19794    pub fn set_text(
19795        &mut self,
19796        text: impl Into<Arc<str>>,
19797        window: &mut Window,
19798        cx: &mut Context<Self>,
19799    ) {
19800        self.transact(window, cx, |this, _, cx| {
19801            this.buffer
19802                .read(cx)
19803                .as_singleton()
19804                .expect("you can only call set_text on editors for singleton buffers")
19805                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19806        });
19807    }
19808
19809    pub fn display_text(&self, cx: &mut App) -> String {
19810        self.display_map
19811            .update(cx, |map, cx| map.snapshot(cx))
19812            .text()
19813    }
19814
19815    fn create_minimap(
19816        &self,
19817        minimap_settings: MinimapSettings,
19818        window: &mut Window,
19819        cx: &mut Context<Self>,
19820    ) -> Option<Entity<Self>> {
19821        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19822            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19823    }
19824
19825    fn initialize_new_minimap(
19826        &self,
19827        minimap_settings: MinimapSettings,
19828        window: &mut Window,
19829        cx: &mut Context<Self>,
19830    ) -> Entity<Self> {
19831        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19832
19833        let mut minimap = Editor::new_internal(
19834            EditorMode::Minimap {
19835                parent: cx.weak_entity(),
19836            },
19837            self.buffer.clone(),
19838            None,
19839            Some(self.display_map.clone()),
19840            window,
19841            cx,
19842        );
19843        minimap.scroll_manager.clone_state(&self.scroll_manager);
19844        minimap.set_text_style_refinement(TextStyleRefinement {
19845            font_size: Some(MINIMAP_FONT_SIZE),
19846            font_weight: Some(MINIMAP_FONT_WEIGHT),
19847            ..Default::default()
19848        });
19849        minimap.update_minimap_configuration(minimap_settings, cx);
19850        cx.new(|_| minimap)
19851    }
19852
19853    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19854        let current_line_highlight = minimap_settings
19855            .current_line_highlight
19856            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19857        self.set_current_line_highlight(Some(current_line_highlight));
19858    }
19859
19860    pub fn minimap(&self) -> Option<&Entity<Self>> {
19861        self.minimap
19862            .as_ref()
19863            .filter(|_| self.minimap_visibility.visible())
19864    }
19865
19866    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19867        let mut wrap_guides = smallvec![];
19868
19869        if self.show_wrap_guides == Some(false) {
19870            return wrap_guides;
19871        }
19872
19873        let settings = self.buffer.read(cx).language_settings(cx);
19874        if settings.show_wrap_guides {
19875            match self.soft_wrap_mode(cx) {
19876                SoftWrap::Column(soft_wrap) => {
19877                    wrap_guides.push((soft_wrap as usize, true));
19878                }
19879                SoftWrap::Bounded(soft_wrap) => {
19880                    wrap_guides.push((soft_wrap as usize, true));
19881                }
19882                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19883            }
19884            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19885        }
19886
19887        wrap_guides
19888    }
19889
19890    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19891        let settings = self.buffer.read(cx).language_settings(cx);
19892        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19893        match mode {
19894            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19895                SoftWrap::None
19896            }
19897            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19898            language_settings::SoftWrap::PreferredLineLength => {
19899                SoftWrap::Column(settings.preferred_line_length)
19900            }
19901            language_settings::SoftWrap::Bounded => {
19902                SoftWrap::Bounded(settings.preferred_line_length)
19903            }
19904        }
19905    }
19906
19907    pub fn set_soft_wrap_mode(
19908        &mut self,
19909        mode: language_settings::SoftWrap,
19910
19911        cx: &mut Context<Self>,
19912    ) {
19913        self.soft_wrap_mode_override = Some(mode);
19914        cx.notify();
19915    }
19916
19917    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19918        self.hard_wrap = hard_wrap;
19919        cx.notify();
19920    }
19921
19922    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19923        self.text_style_refinement = Some(style);
19924    }
19925
19926    /// called by the Element so we know what style we were most recently rendered with.
19927    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19928        // We intentionally do not inform the display map about the minimap style
19929        // so that wrapping is not recalculated and stays consistent for the editor
19930        // and its linked minimap.
19931        if !self.mode.is_minimap() {
19932            let font = style.text.font();
19933            let font_size = style.text.font_size.to_pixels(window.rem_size());
19934            let display_map = self
19935                .placeholder_display_map
19936                .as_ref()
19937                .filter(|_| self.is_empty(cx))
19938                .unwrap_or(&self.display_map);
19939
19940            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19941        }
19942        self.style = Some(style);
19943    }
19944
19945    pub fn style(&self) -> Option<&EditorStyle> {
19946        self.style.as_ref()
19947    }
19948
19949    // Called by the element. This method is not designed to be called outside of the editor
19950    // element's layout code because it does not notify when rewrapping is computed synchronously.
19951    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19952        if self.is_empty(cx) {
19953            self.placeholder_display_map
19954                .as_ref()
19955                .map_or(false, |display_map| {
19956                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19957                })
19958        } else {
19959            self.display_map
19960                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19961        }
19962    }
19963
19964    pub fn set_soft_wrap(&mut self) {
19965        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19966    }
19967
19968    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19969        if self.soft_wrap_mode_override.is_some() {
19970            self.soft_wrap_mode_override.take();
19971        } else {
19972            let soft_wrap = match self.soft_wrap_mode(cx) {
19973                SoftWrap::GitDiff => return,
19974                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19975                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19976                    language_settings::SoftWrap::None
19977                }
19978            };
19979            self.soft_wrap_mode_override = Some(soft_wrap);
19980        }
19981        cx.notify();
19982    }
19983
19984    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19985        let Some(workspace) = self.workspace() else {
19986            return;
19987        };
19988        let fs = workspace.read(cx).app_state().fs.clone();
19989        let current_show = TabBarSettings::get_global(cx).show;
19990        update_settings_file(fs, cx, move |setting, _| {
19991            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19992        });
19993    }
19994
19995    pub fn toggle_indent_guides(
19996        &mut self,
19997        _: &ToggleIndentGuides,
19998        _: &mut Window,
19999        cx: &mut Context<Self>,
20000    ) {
20001        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20002            self.buffer
20003                .read(cx)
20004                .language_settings(cx)
20005                .indent_guides
20006                .enabled
20007        });
20008        self.show_indent_guides = Some(!currently_enabled);
20009        cx.notify();
20010    }
20011
20012    fn should_show_indent_guides(&self) -> Option<bool> {
20013        self.show_indent_guides
20014    }
20015
20016    pub fn toggle_line_numbers(
20017        &mut self,
20018        _: &ToggleLineNumbers,
20019        _: &mut Window,
20020        cx: &mut Context<Self>,
20021    ) {
20022        let mut editor_settings = EditorSettings::get_global(cx).clone();
20023        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20024        EditorSettings::override_global(editor_settings, cx);
20025    }
20026
20027    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20028        if let Some(show_line_numbers) = self.show_line_numbers {
20029            return show_line_numbers;
20030        }
20031        EditorSettings::get_global(cx).gutter.line_numbers
20032    }
20033
20034    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20035        match (
20036            self.use_relative_line_numbers,
20037            EditorSettings::get_global(cx).relative_line_numbers,
20038        ) {
20039            (None, setting) => setting,
20040            (Some(false), _) => RelativeLineNumbers::Disabled,
20041            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20042            (Some(true), _) => RelativeLineNumbers::Enabled,
20043        }
20044    }
20045
20046    pub fn toggle_relative_line_numbers(
20047        &mut self,
20048        _: &ToggleRelativeLineNumbers,
20049        _: &mut Window,
20050        cx: &mut Context<Self>,
20051    ) {
20052        let is_relative = self.relative_line_numbers(cx);
20053        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20054    }
20055
20056    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20057        self.use_relative_line_numbers = is_relative;
20058        cx.notify();
20059    }
20060
20061    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20062        self.show_gutter = show_gutter;
20063        cx.notify();
20064    }
20065
20066    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20067        self.show_scrollbars = ScrollbarAxes {
20068            horizontal: show,
20069            vertical: show,
20070        };
20071        cx.notify();
20072    }
20073
20074    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20075        self.show_scrollbars.vertical = show;
20076        cx.notify();
20077    }
20078
20079    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20080        self.show_scrollbars.horizontal = show;
20081        cx.notify();
20082    }
20083
20084    pub fn set_minimap_visibility(
20085        &mut self,
20086        minimap_visibility: MinimapVisibility,
20087        window: &mut Window,
20088        cx: &mut Context<Self>,
20089    ) {
20090        if self.minimap_visibility != minimap_visibility {
20091            if minimap_visibility.visible() && self.minimap.is_none() {
20092                let minimap_settings = EditorSettings::get_global(cx).minimap;
20093                self.minimap =
20094                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20095            }
20096            self.minimap_visibility = minimap_visibility;
20097            cx.notify();
20098        }
20099    }
20100
20101    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20102        self.set_show_scrollbars(false, cx);
20103        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20104    }
20105
20106    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20107        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20108    }
20109
20110    /// Normally the text in full mode and auto height editors is padded on the
20111    /// left side by roughly half a character width for improved hit testing.
20112    ///
20113    /// Use this method to disable this for cases where this is not wanted (e.g.
20114    /// if you want to align the editor text with some other text above or below)
20115    /// or if you want to add this padding to single-line editors.
20116    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20117        self.offset_content = offset_content;
20118        cx.notify();
20119    }
20120
20121    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20122        self.show_line_numbers = Some(show_line_numbers);
20123        cx.notify();
20124    }
20125
20126    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20127        self.disable_expand_excerpt_buttons = true;
20128        cx.notify();
20129    }
20130
20131    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20132        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20133        cx.notify();
20134    }
20135
20136    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20137        self.show_code_actions = Some(show_code_actions);
20138        cx.notify();
20139    }
20140
20141    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20142        self.show_runnables = Some(show_runnables);
20143        cx.notify();
20144    }
20145
20146    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20147        self.show_breakpoints = Some(show_breakpoints);
20148        cx.notify();
20149    }
20150
20151    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20152        if self.display_map.read(cx).masked != masked {
20153            self.display_map.update(cx, |map, _| map.masked = masked);
20154        }
20155        cx.notify()
20156    }
20157
20158    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20159        self.show_wrap_guides = Some(show_wrap_guides);
20160        cx.notify();
20161    }
20162
20163    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20164        self.show_indent_guides = Some(show_indent_guides);
20165        cx.notify();
20166    }
20167
20168    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20169        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20170            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20171                && let Some(dir) = file.abs_path(cx).parent()
20172            {
20173                return Some(dir.to_owned());
20174            }
20175        }
20176
20177        None
20178    }
20179
20180    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20181        self.active_excerpt(cx)?
20182            .1
20183            .read(cx)
20184            .file()
20185            .and_then(|f| f.as_local())
20186    }
20187
20188    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20189        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20190            let buffer = buffer.read(cx);
20191            if let Some(project_path) = buffer.project_path(cx) {
20192                let project = self.project()?.read(cx);
20193                project.absolute_path(&project_path, cx)
20194            } else {
20195                buffer
20196                    .file()
20197                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20198            }
20199        })
20200    }
20201
20202    pub fn reveal_in_finder(
20203        &mut self,
20204        _: &RevealInFileManager,
20205        _window: &mut Window,
20206        cx: &mut Context<Self>,
20207    ) {
20208        if let Some(target) = self.target_file(cx) {
20209            cx.reveal_path(&target.abs_path(cx));
20210        }
20211    }
20212
20213    pub fn copy_path(
20214        &mut self,
20215        _: &zed_actions::workspace::CopyPath,
20216        _window: &mut Window,
20217        cx: &mut Context<Self>,
20218    ) {
20219        if let Some(path) = self.target_file_abs_path(cx)
20220            && let Some(path) = path.to_str()
20221        {
20222            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20223        } else {
20224            cx.propagate();
20225        }
20226    }
20227
20228    pub fn copy_relative_path(
20229        &mut self,
20230        _: &zed_actions::workspace::CopyRelativePath,
20231        _window: &mut Window,
20232        cx: &mut Context<Self>,
20233    ) {
20234        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20235            let project = self.project()?.read(cx);
20236            let path = buffer.read(cx).file()?.path();
20237            let path = path.display(project.path_style(cx));
20238            Some(path)
20239        }) {
20240            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20241        } else {
20242            cx.propagate();
20243        }
20244    }
20245
20246    /// Returns the project path for the editor's buffer, if any buffer is
20247    /// opened in the editor.
20248    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20249        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20250            buffer.read(cx).project_path(cx)
20251        } else {
20252            None
20253        }
20254    }
20255
20256    // Returns true if the editor handled a go-to-line request
20257    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20258        maybe!({
20259            let breakpoint_store = self.breakpoint_store.as_ref()?;
20260
20261            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20262            else {
20263                self.clear_row_highlights::<ActiveDebugLine>();
20264                return None;
20265            };
20266
20267            let position = active_stack_frame.position;
20268            let buffer_id = position.buffer_id?;
20269            let snapshot = self
20270                .project
20271                .as_ref()?
20272                .read(cx)
20273                .buffer_for_id(buffer_id, cx)?
20274                .read(cx)
20275                .snapshot();
20276
20277            let mut handled = false;
20278            for (id, ExcerptRange { context, .. }) in
20279                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20280            {
20281                if context.start.cmp(&position, &snapshot).is_ge()
20282                    || context.end.cmp(&position, &snapshot).is_lt()
20283                {
20284                    continue;
20285                }
20286                let snapshot = self.buffer.read(cx).snapshot(cx);
20287                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20288
20289                handled = true;
20290                self.clear_row_highlights::<ActiveDebugLine>();
20291
20292                self.go_to_line::<ActiveDebugLine>(
20293                    multibuffer_anchor,
20294                    Some(cx.theme().colors().editor_debugger_active_line_background),
20295                    window,
20296                    cx,
20297                );
20298
20299                cx.notify();
20300            }
20301
20302            handled.then_some(())
20303        })
20304        .is_some()
20305    }
20306
20307    pub fn copy_file_name_without_extension(
20308        &mut self,
20309        _: &CopyFileNameWithoutExtension,
20310        _: &mut Window,
20311        cx: &mut Context<Self>,
20312    ) {
20313        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20314            let file = buffer.read(cx).file()?;
20315            file.path().file_stem()
20316        }) {
20317            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20318        }
20319    }
20320
20321    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20322        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20323            let file = buffer.read(cx).file()?;
20324            Some(file.file_name(cx))
20325        }) {
20326            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20327        }
20328    }
20329
20330    pub fn toggle_git_blame(
20331        &mut self,
20332        _: &::git::Blame,
20333        window: &mut Window,
20334        cx: &mut Context<Self>,
20335    ) {
20336        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20337
20338        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20339            self.start_git_blame(true, window, cx);
20340        }
20341
20342        cx.notify();
20343    }
20344
20345    pub fn toggle_git_blame_inline(
20346        &mut self,
20347        _: &ToggleGitBlameInline,
20348        window: &mut Window,
20349        cx: &mut Context<Self>,
20350    ) {
20351        self.toggle_git_blame_inline_internal(true, window, cx);
20352        cx.notify();
20353    }
20354
20355    pub fn open_git_blame_commit(
20356        &mut self,
20357        _: &OpenGitBlameCommit,
20358        window: &mut Window,
20359        cx: &mut Context<Self>,
20360    ) {
20361        self.open_git_blame_commit_internal(window, cx);
20362    }
20363
20364    fn open_git_blame_commit_internal(
20365        &mut self,
20366        window: &mut Window,
20367        cx: &mut Context<Self>,
20368    ) -> Option<()> {
20369        let blame = self.blame.as_ref()?;
20370        let snapshot = self.snapshot(window, cx);
20371        let cursor = self
20372            .selections
20373            .newest::<Point>(&snapshot.display_snapshot)
20374            .head();
20375        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20376        let (_, blame_entry) = blame
20377            .update(cx, |blame, cx| {
20378                blame
20379                    .blame_for_rows(
20380                        &[RowInfo {
20381                            buffer_id: Some(buffer.remote_id()),
20382                            buffer_row: Some(point.row),
20383                            ..Default::default()
20384                        }],
20385                        cx,
20386                    )
20387                    .next()
20388            })
20389            .flatten()?;
20390        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20391        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20392        let workspace = self.workspace()?.downgrade();
20393        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20394        None
20395    }
20396
20397    pub fn git_blame_inline_enabled(&self) -> bool {
20398        self.git_blame_inline_enabled
20399    }
20400
20401    pub fn toggle_selection_menu(
20402        &mut self,
20403        _: &ToggleSelectionMenu,
20404        _: &mut Window,
20405        cx: &mut Context<Self>,
20406    ) {
20407        self.show_selection_menu = self
20408            .show_selection_menu
20409            .map(|show_selections_menu| !show_selections_menu)
20410            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20411
20412        cx.notify();
20413    }
20414
20415    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20416        self.show_selection_menu
20417            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20418    }
20419
20420    fn start_git_blame(
20421        &mut self,
20422        user_triggered: bool,
20423        window: &mut Window,
20424        cx: &mut Context<Self>,
20425    ) {
20426        if let Some(project) = self.project() {
20427            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20428                && buffer.read(cx).file().is_none()
20429            {
20430                return;
20431            }
20432
20433            let focused = self.focus_handle(cx).contains_focused(window, cx);
20434
20435            let project = project.clone();
20436            let blame = cx
20437                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20438            self.blame_subscription =
20439                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20440            self.blame = Some(blame);
20441        }
20442    }
20443
20444    fn toggle_git_blame_inline_internal(
20445        &mut self,
20446        user_triggered: bool,
20447        window: &mut Window,
20448        cx: &mut Context<Self>,
20449    ) {
20450        if self.git_blame_inline_enabled {
20451            self.git_blame_inline_enabled = false;
20452            self.show_git_blame_inline = false;
20453            self.show_git_blame_inline_delay_task.take();
20454        } else {
20455            self.git_blame_inline_enabled = true;
20456            self.start_git_blame_inline(user_triggered, window, cx);
20457        }
20458
20459        cx.notify();
20460    }
20461
20462    fn start_git_blame_inline(
20463        &mut self,
20464        user_triggered: bool,
20465        window: &mut Window,
20466        cx: &mut Context<Self>,
20467    ) {
20468        self.start_git_blame(user_triggered, window, cx);
20469
20470        if ProjectSettings::get_global(cx)
20471            .git
20472            .inline_blame_delay()
20473            .is_some()
20474        {
20475            self.start_inline_blame_timer(window, cx);
20476        } else {
20477            self.show_git_blame_inline = true
20478        }
20479    }
20480
20481    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20482        self.blame.as_ref()
20483    }
20484
20485    pub fn show_git_blame_gutter(&self) -> bool {
20486        self.show_git_blame_gutter
20487    }
20488
20489    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20490        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20491    }
20492
20493    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20494        self.show_git_blame_inline
20495            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20496            && !self.newest_selection_head_on_empty_line(cx)
20497            && self.has_blame_entries(cx)
20498    }
20499
20500    fn has_blame_entries(&self, cx: &App) -> bool {
20501        self.blame()
20502            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20503    }
20504
20505    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20506        let cursor_anchor = self.selections.newest_anchor().head();
20507
20508        let snapshot = self.buffer.read(cx).snapshot(cx);
20509        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20510
20511        snapshot.line_len(buffer_row) == 0
20512    }
20513
20514    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20515        let buffer_and_selection = maybe!({
20516            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20517            let selection_range = selection.range();
20518
20519            let multi_buffer = self.buffer().read(cx);
20520            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20521            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20522
20523            let (buffer, range, _) = if selection.reversed {
20524                buffer_ranges.first()
20525            } else {
20526                buffer_ranges.last()
20527            }?;
20528
20529            let selection = text::ToPoint::to_point(&range.start, buffer).row
20530                ..text::ToPoint::to_point(&range.end, buffer).row;
20531            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20532        });
20533
20534        let Some((buffer, selection)) = buffer_and_selection else {
20535            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20536        };
20537
20538        let Some(project) = self.project() else {
20539            return Task::ready(Err(anyhow!("editor does not have project")));
20540        };
20541
20542        project.update(cx, |project, cx| {
20543            project.get_permalink_to_line(&buffer, selection, cx)
20544        })
20545    }
20546
20547    pub fn copy_permalink_to_line(
20548        &mut self,
20549        _: &CopyPermalinkToLine,
20550        window: &mut Window,
20551        cx: &mut Context<Self>,
20552    ) {
20553        let permalink_task = self.get_permalink_to_line(cx);
20554        let workspace = self.workspace();
20555
20556        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20557            Ok(permalink) => {
20558                cx.update(|_, cx| {
20559                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20560                })
20561                .ok();
20562            }
20563            Err(err) => {
20564                let message = format!("Failed to copy permalink: {err}");
20565
20566                anyhow::Result::<()>::Err(err).log_err();
20567
20568                if let Some(workspace) = workspace {
20569                    workspace
20570                        .update_in(cx, |workspace, _, cx| {
20571                            struct CopyPermalinkToLine;
20572
20573                            workspace.show_toast(
20574                                Toast::new(
20575                                    NotificationId::unique::<CopyPermalinkToLine>(),
20576                                    message,
20577                                ),
20578                                cx,
20579                            )
20580                        })
20581                        .ok();
20582                }
20583            }
20584        })
20585        .detach();
20586    }
20587
20588    pub fn copy_file_location(
20589        &mut self,
20590        _: &CopyFileLocation,
20591        _: &mut Window,
20592        cx: &mut Context<Self>,
20593    ) {
20594        let selection = self
20595            .selections
20596            .newest::<Point>(&self.display_snapshot(cx))
20597            .start
20598            .row
20599            + 1;
20600        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20601            let project = self.project()?.read(cx);
20602            let file = buffer.read(cx).file()?;
20603            let path = file.path().display(project.path_style(cx));
20604
20605            Some(format!("{path}:{selection}"))
20606        }) {
20607            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
20608        }
20609    }
20610
20611    pub fn open_permalink_to_line(
20612        &mut self,
20613        _: &OpenPermalinkToLine,
20614        window: &mut Window,
20615        cx: &mut Context<Self>,
20616    ) {
20617        let permalink_task = self.get_permalink_to_line(cx);
20618        let workspace = self.workspace();
20619
20620        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20621            Ok(permalink) => {
20622                cx.update(|_, cx| {
20623                    cx.open_url(permalink.as_ref());
20624                })
20625                .ok();
20626            }
20627            Err(err) => {
20628                let message = format!("Failed to open permalink: {err}");
20629
20630                anyhow::Result::<()>::Err(err).log_err();
20631
20632                if let Some(workspace) = workspace {
20633                    workspace
20634                        .update(cx, |workspace, cx| {
20635                            struct OpenPermalinkToLine;
20636
20637                            workspace.show_toast(
20638                                Toast::new(
20639                                    NotificationId::unique::<OpenPermalinkToLine>(),
20640                                    message,
20641                                ),
20642                                cx,
20643                            )
20644                        })
20645                        .ok();
20646                }
20647            }
20648        })
20649        .detach();
20650    }
20651
20652    pub fn insert_uuid_v4(
20653        &mut self,
20654        _: &InsertUuidV4,
20655        window: &mut Window,
20656        cx: &mut Context<Self>,
20657    ) {
20658        self.insert_uuid(UuidVersion::V4, window, cx);
20659    }
20660
20661    pub fn insert_uuid_v7(
20662        &mut self,
20663        _: &InsertUuidV7,
20664        window: &mut Window,
20665        cx: &mut Context<Self>,
20666    ) {
20667        self.insert_uuid(UuidVersion::V7, window, cx);
20668    }
20669
20670    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20671        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20672        self.transact(window, cx, |this, window, cx| {
20673            let edits = this
20674                .selections
20675                .all::<Point>(&this.display_snapshot(cx))
20676                .into_iter()
20677                .map(|selection| {
20678                    let uuid = match version {
20679                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20680                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20681                    };
20682
20683                    (selection.range(), uuid.to_string())
20684                });
20685            this.edit(edits, cx);
20686            this.refresh_edit_prediction(true, false, window, cx);
20687        });
20688    }
20689
20690    pub fn open_selections_in_multibuffer(
20691        &mut self,
20692        _: &OpenSelectionsInMultibuffer,
20693        window: &mut Window,
20694        cx: &mut Context<Self>,
20695    ) {
20696        let multibuffer = self.buffer.read(cx);
20697
20698        let Some(buffer) = multibuffer.as_singleton() else {
20699            return;
20700        };
20701
20702        let Some(workspace) = self.workspace() else {
20703            return;
20704        };
20705
20706        let title = multibuffer.title(cx).to_string();
20707
20708        let locations = self
20709            .selections
20710            .all_anchors(&self.display_snapshot(cx))
20711            .iter()
20712            .map(|selection| {
20713                (
20714                    buffer.clone(),
20715                    (selection.start.text_anchor..selection.end.text_anchor)
20716                        .to_point(buffer.read(cx)),
20717                )
20718            })
20719            .into_group_map();
20720
20721        cx.spawn_in(window, async move |_, cx| {
20722            workspace.update_in(cx, |workspace, window, cx| {
20723                Self::open_locations_in_multibuffer(
20724                    workspace,
20725                    locations,
20726                    format!("Selections for '{title}'"),
20727                    false,
20728                    MultibufferSelectionMode::All,
20729                    window,
20730                    cx,
20731                );
20732            })
20733        })
20734        .detach();
20735    }
20736
20737    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20738    /// last highlight added will be used.
20739    ///
20740    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20741    pub fn highlight_rows<T: 'static>(
20742        &mut self,
20743        range: Range<Anchor>,
20744        color: Hsla,
20745        options: RowHighlightOptions,
20746        cx: &mut Context<Self>,
20747    ) {
20748        let snapshot = self.buffer().read(cx).snapshot(cx);
20749        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20750        let ix = row_highlights.binary_search_by(|highlight| {
20751            Ordering::Equal
20752                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20753                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20754        });
20755
20756        if let Err(mut ix) = ix {
20757            let index = post_inc(&mut self.highlight_order);
20758
20759            // If this range intersects with the preceding highlight, then merge it with
20760            // the preceding highlight. Otherwise insert a new highlight.
20761            let mut merged = false;
20762            if ix > 0 {
20763                let prev_highlight = &mut row_highlights[ix - 1];
20764                if prev_highlight
20765                    .range
20766                    .end
20767                    .cmp(&range.start, &snapshot)
20768                    .is_ge()
20769                {
20770                    ix -= 1;
20771                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20772                        prev_highlight.range.end = range.end;
20773                    }
20774                    merged = true;
20775                    prev_highlight.index = index;
20776                    prev_highlight.color = color;
20777                    prev_highlight.options = options;
20778                }
20779            }
20780
20781            if !merged {
20782                row_highlights.insert(
20783                    ix,
20784                    RowHighlight {
20785                        range,
20786                        index,
20787                        color,
20788                        options,
20789                        type_id: TypeId::of::<T>(),
20790                    },
20791                );
20792            }
20793
20794            // If any of the following highlights intersect with this one, merge them.
20795            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20796                let highlight = &row_highlights[ix];
20797                if next_highlight
20798                    .range
20799                    .start
20800                    .cmp(&highlight.range.end, &snapshot)
20801                    .is_le()
20802                {
20803                    if next_highlight
20804                        .range
20805                        .end
20806                        .cmp(&highlight.range.end, &snapshot)
20807                        .is_gt()
20808                    {
20809                        row_highlights[ix].range.end = next_highlight.range.end;
20810                    }
20811                    row_highlights.remove(ix + 1);
20812                } else {
20813                    break;
20814                }
20815            }
20816        }
20817    }
20818
20819    /// Remove any highlighted row ranges of the given type that intersect the
20820    /// given ranges.
20821    pub fn remove_highlighted_rows<T: 'static>(
20822        &mut self,
20823        ranges_to_remove: Vec<Range<Anchor>>,
20824        cx: &mut Context<Self>,
20825    ) {
20826        let snapshot = self.buffer().read(cx).snapshot(cx);
20827        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20828        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20829        row_highlights.retain(|highlight| {
20830            while let Some(range_to_remove) = ranges_to_remove.peek() {
20831                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20832                    Ordering::Less | Ordering::Equal => {
20833                        ranges_to_remove.next();
20834                    }
20835                    Ordering::Greater => {
20836                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20837                            Ordering::Less | Ordering::Equal => {
20838                                return false;
20839                            }
20840                            Ordering::Greater => break,
20841                        }
20842                    }
20843                }
20844            }
20845
20846            true
20847        })
20848    }
20849
20850    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20851    pub fn clear_row_highlights<T: 'static>(&mut self) {
20852        self.highlighted_rows.remove(&TypeId::of::<T>());
20853    }
20854
20855    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20856    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20857        self.highlighted_rows
20858            .get(&TypeId::of::<T>())
20859            .map_or(&[] as &[_], |vec| vec.as_slice())
20860            .iter()
20861            .map(|highlight| (highlight.range.clone(), highlight.color))
20862    }
20863
20864    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20865    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20866    /// Allows to ignore certain kinds of highlights.
20867    pub fn highlighted_display_rows(
20868        &self,
20869        window: &mut Window,
20870        cx: &mut App,
20871    ) -> BTreeMap<DisplayRow, LineHighlight> {
20872        let snapshot = self.snapshot(window, cx);
20873        let mut used_highlight_orders = HashMap::default();
20874        self.highlighted_rows
20875            .iter()
20876            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20877            .fold(
20878                BTreeMap::<DisplayRow, LineHighlight>::new(),
20879                |mut unique_rows, highlight| {
20880                    let start = highlight.range.start.to_display_point(&snapshot);
20881                    let end = highlight.range.end.to_display_point(&snapshot);
20882                    let start_row = start.row().0;
20883                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
20884                    {
20885                        end.row().0.saturating_sub(1)
20886                    } else {
20887                        end.row().0
20888                    };
20889                    for row in start_row..=end_row {
20890                        let used_index =
20891                            used_highlight_orders.entry(row).or_insert(highlight.index);
20892                        if highlight.index >= *used_index {
20893                            *used_index = highlight.index;
20894                            unique_rows.insert(
20895                                DisplayRow(row),
20896                                LineHighlight {
20897                                    include_gutter: highlight.options.include_gutter,
20898                                    border: None,
20899                                    background: highlight.color.into(),
20900                                    type_id: Some(highlight.type_id),
20901                                },
20902                            );
20903                        }
20904                    }
20905                    unique_rows
20906                },
20907            )
20908    }
20909
20910    pub fn highlighted_display_row_for_autoscroll(
20911        &self,
20912        snapshot: &DisplaySnapshot,
20913    ) -> Option<DisplayRow> {
20914        self.highlighted_rows
20915            .values()
20916            .flat_map(|highlighted_rows| highlighted_rows.iter())
20917            .filter_map(|highlight| {
20918                if highlight.options.autoscroll {
20919                    Some(highlight.range.start.to_display_point(snapshot).row())
20920                } else {
20921                    None
20922                }
20923            })
20924            .min()
20925    }
20926
20927    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20928        self.highlight_background::<SearchWithinRange>(
20929            ranges,
20930            |colors| colors.colors().editor_document_highlight_read_background,
20931            cx,
20932        )
20933    }
20934
20935    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20936        self.breadcrumb_header = Some(new_header);
20937    }
20938
20939    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20940        self.clear_background_highlights::<SearchWithinRange>(cx);
20941    }
20942
20943    pub fn highlight_background<T: 'static>(
20944        &mut self,
20945        ranges: &[Range<Anchor>],
20946        color_fetcher: fn(&Theme) -> Hsla,
20947        cx: &mut Context<Self>,
20948    ) {
20949        self.background_highlights.insert(
20950            HighlightKey::Type(TypeId::of::<T>()),
20951            (color_fetcher, Arc::from(ranges)),
20952        );
20953        self.scrollbar_marker_state.dirty = true;
20954        cx.notify();
20955    }
20956
20957    pub fn highlight_background_key<T: 'static>(
20958        &mut self,
20959        key: usize,
20960        ranges: &[Range<Anchor>],
20961        color_fetcher: fn(&Theme) -> Hsla,
20962        cx: &mut Context<Self>,
20963    ) {
20964        self.background_highlights.insert(
20965            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20966            (color_fetcher, Arc::from(ranges)),
20967        );
20968        self.scrollbar_marker_state.dirty = true;
20969        cx.notify();
20970    }
20971
20972    pub fn clear_background_highlights<T: 'static>(
20973        &mut self,
20974        cx: &mut Context<Self>,
20975    ) -> Option<BackgroundHighlight> {
20976        let text_highlights = self
20977            .background_highlights
20978            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20979        if !text_highlights.1.is_empty() {
20980            self.scrollbar_marker_state.dirty = true;
20981            cx.notify();
20982        }
20983        Some(text_highlights)
20984    }
20985
20986    pub fn highlight_gutter<T: 'static>(
20987        &mut self,
20988        ranges: impl Into<Vec<Range<Anchor>>>,
20989        color_fetcher: fn(&App) -> Hsla,
20990        cx: &mut Context<Self>,
20991    ) {
20992        self.gutter_highlights
20993            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20994        cx.notify();
20995    }
20996
20997    pub fn clear_gutter_highlights<T: 'static>(
20998        &mut self,
20999        cx: &mut Context<Self>,
21000    ) -> Option<GutterHighlight> {
21001        cx.notify();
21002        self.gutter_highlights.remove(&TypeId::of::<T>())
21003    }
21004
21005    pub fn insert_gutter_highlight<T: 'static>(
21006        &mut self,
21007        range: Range<Anchor>,
21008        color_fetcher: fn(&App) -> Hsla,
21009        cx: &mut Context<Self>,
21010    ) {
21011        let snapshot = self.buffer().read(cx).snapshot(cx);
21012        let mut highlights = self
21013            .gutter_highlights
21014            .remove(&TypeId::of::<T>())
21015            .map(|(_, highlights)| highlights)
21016            .unwrap_or_default();
21017        let ix = highlights.binary_search_by(|highlight| {
21018            Ordering::Equal
21019                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21020                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21021        });
21022        if let Err(ix) = ix {
21023            highlights.insert(ix, range);
21024        }
21025        self.gutter_highlights
21026            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21027    }
21028
21029    pub fn remove_gutter_highlights<T: 'static>(
21030        &mut self,
21031        ranges_to_remove: Vec<Range<Anchor>>,
21032        cx: &mut Context<Self>,
21033    ) {
21034        let snapshot = self.buffer().read(cx).snapshot(cx);
21035        let Some((color_fetcher, mut gutter_highlights)) =
21036            self.gutter_highlights.remove(&TypeId::of::<T>())
21037        else {
21038            return;
21039        };
21040        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21041        gutter_highlights.retain(|highlight| {
21042            while let Some(range_to_remove) = ranges_to_remove.peek() {
21043                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21044                    Ordering::Less | Ordering::Equal => {
21045                        ranges_to_remove.next();
21046                    }
21047                    Ordering::Greater => {
21048                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21049                            Ordering::Less | Ordering::Equal => {
21050                                return false;
21051                            }
21052                            Ordering::Greater => break,
21053                        }
21054                    }
21055                }
21056            }
21057
21058            true
21059        });
21060        self.gutter_highlights
21061            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21062    }
21063
21064    #[cfg(feature = "test-support")]
21065    pub fn all_text_highlights(
21066        &self,
21067        window: &mut Window,
21068        cx: &mut Context<Self>,
21069    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21070        let snapshot = self.snapshot(window, cx);
21071        self.display_map.update(cx, |display_map, _| {
21072            display_map
21073                .all_text_highlights()
21074                .map(|highlight| {
21075                    let (style, ranges) = highlight.as_ref();
21076                    (
21077                        *style,
21078                        ranges
21079                            .iter()
21080                            .map(|range| range.clone().to_display_points(&snapshot))
21081                            .collect(),
21082                    )
21083                })
21084                .collect()
21085        })
21086    }
21087
21088    #[cfg(feature = "test-support")]
21089    pub fn all_text_background_highlights(
21090        &self,
21091        window: &mut Window,
21092        cx: &mut Context<Self>,
21093    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21094        let snapshot = self.snapshot(window, cx);
21095        let buffer = &snapshot.buffer_snapshot();
21096        let start = buffer.anchor_before(MultiBufferOffset(0));
21097        let end = buffer.anchor_after(buffer.len());
21098        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21099    }
21100
21101    #[cfg(any(test, feature = "test-support"))]
21102    pub fn sorted_background_highlights_in_range(
21103        &self,
21104        search_range: Range<Anchor>,
21105        display_snapshot: &DisplaySnapshot,
21106        theme: &Theme,
21107    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21108        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21109        res.sort_by(|a, b| {
21110            a.0.start
21111                .cmp(&b.0.start)
21112                .then_with(|| a.0.end.cmp(&b.0.end))
21113                .then_with(|| a.1.cmp(&b.1))
21114        });
21115        res
21116    }
21117
21118    #[cfg(feature = "test-support")]
21119    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21120        let snapshot = self.buffer().read(cx).snapshot(cx);
21121
21122        let highlights = self
21123            .background_highlights
21124            .get(&HighlightKey::Type(TypeId::of::<
21125                items::BufferSearchHighlights,
21126            >()));
21127
21128        if let Some((_color, ranges)) = highlights {
21129            ranges
21130                .iter()
21131                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21132                .collect_vec()
21133        } else {
21134            vec![]
21135        }
21136    }
21137
21138    fn document_highlights_for_position<'a>(
21139        &'a self,
21140        position: Anchor,
21141        buffer: &'a MultiBufferSnapshot,
21142    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21143        let read_highlights = self
21144            .background_highlights
21145            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21146            .map(|h| &h.1);
21147        let write_highlights = self
21148            .background_highlights
21149            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21150            .map(|h| &h.1);
21151        let left_position = position.bias_left(buffer);
21152        let right_position = position.bias_right(buffer);
21153        read_highlights
21154            .into_iter()
21155            .chain(write_highlights)
21156            .flat_map(move |ranges| {
21157                let start_ix = match ranges.binary_search_by(|probe| {
21158                    let cmp = probe.end.cmp(&left_position, buffer);
21159                    if cmp.is_ge() {
21160                        Ordering::Greater
21161                    } else {
21162                        Ordering::Less
21163                    }
21164                }) {
21165                    Ok(i) | Err(i) => i,
21166                };
21167
21168                ranges[start_ix..]
21169                    .iter()
21170                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21171            })
21172    }
21173
21174    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21175        self.background_highlights
21176            .get(&HighlightKey::Type(TypeId::of::<T>()))
21177            .is_some_and(|(_, highlights)| !highlights.is_empty())
21178    }
21179
21180    /// Returns all background highlights for a given range.
21181    ///
21182    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21183    pub fn background_highlights_in_range(
21184        &self,
21185        search_range: Range<Anchor>,
21186        display_snapshot: &DisplaySnapshot,
21187        theme: &Theme,
21188    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21189        let mut results = Vec::new();
21190        for (color_fetcher, ranges) in self.background_highlights.values() {
21191            let color = color_fetcher(theme);
21192            let start_ix = match ranges.binary_search_by(|probe| {
21193                let cmp = probe
21194                    .end
21195                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21196                if cmp.is_gt() {
21197                    Ordering::Greater
21198                } else {
21199                    Ordering::Less
21200                }
21201            }) {
21202                Ok(i) | Err(i) => i,
21203            };
21204            for range in &ranges[start_ix..] {
21205                if range
21206                    .start
21207                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21208                    .is_ge()
21209                {
21210                    break;
21211                }
21212
21213                let start = range.start.to_display_point(display_snapshot);
21214                let end = range.end.to_display_point(display_snapshot);
21215                results.push((start..end, color))
21216            }
21217        }
21218        results
21219    }
21220
21221    pub fn gutter_highlights_in_range(
21222        &self,
21223        search_range: Range<Anchor>,
21224        display_snapshot: &DisplaySnapshot,
21225        cx: &App,
21226    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21227        let mut results = Vec::new();
21228        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21229            let color = color_fetcher(cx);
21230            let start_ix = match ranges.binary_search_by(|probe| {
21231                let cmp = probe
21232                    .end
21233                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21234                if cmp.is_gt() {
21235                    Ordering::Greater
21236                } else {
21237                    Ordering::Less
21238                }
21239            }) {
21240                Ok(i) | Err(i) => i,
21241            };
21242            for range in &ranges[start_ix..] {
21243                if range
21244                    .start
21245                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21246                    .is_ge()
21247                {
21248                    break;
21249                }
21250
21251                let start = range.start.to_display_point(display_snapshot);
21252                let end = range.end.to_display_point(display_snapshot);
21253                results.push((start..end, color))
21254            }
21255        }
21256        results
21257    }
21258
21259    /// Get the text ranges corresponding to the redaction query
21260    pub fn redacted_ranges(
21261        &self,
21262        search_range: Range<Anchor>,
21263        display_snapshot: &DisplaySnapshot,
21264        cx: &App,
21265    ) -> Vec<Range<DisplayPoint>> {
21266        display_snapshot
21267            .buffer_snapshot()
21268            .redacted_ranges(search_range, |file| {
21269                if let Some(file) = file {
21270                    file.is_private()
21271                        && EditorSettings::get(
21272                            Some(SettingsLocation {
21273                                worktree_id: file.worktree_id(cx),
21274                                path: file.path().as_ref(),
21275                            }),
21276                            cx,
21277                        )
21278                        .redact_private_values
21279                } else {
21280                    false
21281                }
21282            })
21283            .map(|range| {
21284                range.start.to_display_point(display_snapshot)
21285                    ..range.end.to_display_point(display_snapshot)
21286            })
21287            .collect()
21288    }
21289
21290    pub fn highlight_text_key<T: 'static>(
21291        &mut self,
21292        key: usize,
21293        ranges: Vec<Range<Anchor>>,
21294        style: HighlightStyle,
21295        merge: bool,
21296        cx: &mut Context<Self>,
21297    ) {
21298        self.display_map.update(cx, |map, cx| {
21299            map.highlight_text(
21300                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21301                ranges,
21302                style,
21303                merge,
21304                cx,
21305            );
21306        });
21307        cx.notify();
21308    }
21309
21310    pub fn highlight_text<T: 'static>(
21311        &mut self,
21312        ranges: Vec<Range<Anchor>>,
21313        style: HighlightStyle,
21314        cx: &mut Context<Self>,
21315    ) {
21316        self.display_map.update(cx, |map, cx| {
21317            map.highlight_text(
21318                HighlightKey::Type(TypeId::of::<T>()),
21319                ranges,
21320                style,
21321                false,
21322                cx,
21323            )
21324        });
21325        cx.notify();
21326    }
21327
21328    pub fn text_highlights<'a, T: 'static>(
21329        &'a self,
21330        cx: &'a App,
21331    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21332        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21333    }
21334
21335    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21336        let cleared = self
21337            .display_map
21338            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21339        if cleared {
21340            cx.notify();
21341        }
21342    }
21343
21344    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21345        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21346            && self.focus_handle.is_focused(window)
21347    }
21348
21349    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21350        self.show_cursor_when_unfocused = is_enabled;
21351        cx.notify();
21352    }
21353
21354    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21355        cx.notify();
21356    }
21357
21358    fn on_debug_session_event(
21359        &mut self,
21360        _session: Entity<Session>,
21361        event: &SessionEvent,
21362        cx: &mut Context<Self>,
21363    ) {
21364        if let SessionEvent::InvalidateInlineValue = event {
21365            self.refresh_inline_values(cx);
21366        }
21367    }
21368
21369    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21370        let Some(project) = self.project.clone() else {
21371            return;
21372        };
21373
21374        if !self.inline_value_cache.enabled {
21375            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21376            self.splice_inlays(&inlays, Vec::new(), cx);
21377            return;
21378        }
21379
21380        let current_execution_position = self
21381            .highlighted_rows
21382            .get(&TypeId::of::<ActiveDebugLine>())
21383            .and_then(|lines| lines.last().map(|line| line.range.end));
21384
21385        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21386            let inline_values = editor
21387                .update(cx, |editor, cx| {
21388                    let Some(current_execution_position) = current_execution_position else {
21389                        return Some(Task::ready(Ok(Vec::new())));
21390                    };
21391
21392                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21393                        let snapshot = buffer.snapshot(cx);
21394
21395                        let excerpt = snapshot.excerpt_containing(
21396                            current_execution_position..current_execution_position,
21397                        )?;
21398
21399                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21400                    })?;
21401
21402                    let range =
21403                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21404
21405                    project.inline_values(buffer, range, cx)
21406                })
21407                .ok()
21408                .flatten()?
21409                .await
21410                .context("refreshing debugger inlays")
21411                .log_err()?;
21412
21413            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21414
21415            for (buffer_id, inline_value) in inline_values
21416                .into_iter()
21417                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21418            {
21419                buffer_inline_values
21420                    .entry(buffer_id)
21421                    .or_default()
21422                    .push(inline_value);
21423            }
21424
21425            editor
21426                .update(cx, |editor, cx| {
21427                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21428                    let mut new_inlays = Vec::default();
21429
21430                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21431                        let buffer_id = buffer_snapshot.remote_id();
21432                        buffer_inline_values
21433                            .get(&buffer_id)
21434                            .into_iter()
21435                            .flatten()
21436                            .for_each(|hint| {
21437                                let inlay = Inlay::debugger(
21438                                    post_inc(&mut editor.next_inlay_id),
21439                                    Anchor::in_buffer(excerpt_id, hint.position),
21440                                    hint.text(),
21441                                );
21442                                if !inlay.text().chars().contains(&'\n') {
21443                                    new_inlays.push(inlay);
21444                                }
21445                            });
21446                    }
21447
21448                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21449                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21450
21451                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21452                })
21453                .ok()?;
21454            Some(())
21455        });
21456    }
21457
21458    fn on_buffer_event(
21459        &mut self,
21460        multibuffer: &Entity<MultiBuffer>,
21461        event: &multi_buffer::Event,
21462        window: &mut Window,
21463        cx: &mut Context<Self>,
21464    ) {
21465        match event {
21466            multi_buffer::Event::Edited { edited_buffer } => {
21467                self.scrollbar_marker_state.dirty = true;
21468                self.active_indent_guides_state.dirty = true;
21469                self.refresh_active_diagnostics(cx);
21470                self.refresh_code_actions(window, cx);
21471                self.refresh_single_line_folds(window, cx);
21472                self.refresh_matching_bracket_highlights(window, cx);
21473                if self.has_active_edit_prediction() {
21474                    self.update_visible_edit_prediction(window, cx);
21475                }
21476
21477                if let Some(buffer) = edited_buffer {
21478                    if buffer.read(cx).file().is_none() {
21479                        cx.emit(EditorEvent::TitleChanged);
21480                    }
21481
21482                    if self.project.is_some() {
21483                        let buffer_id = buffer.read(cx).remote_id();
21484                        self.register_buffer(buffer_id, cx);
21485                        self.update_lsp_data(Some(buffer_id), window, cx);
21486                        self.refresh_inlay_hints(
21487                            InlayHintRefreshReason::BufferEdited(buffer_id),
21488                            cx,
21489                        );
21490                    }
21491                }
21492
21493                cx.emit(EditorEvent::BufferEdited);
21494                cx.emit(SearchEvent::MatchesInvalidated);
21495
21496                let Some(project) = &self.project else { return };
21497                let (telemetry, is_via_ssh) = {
21498                    let project = project.read(cx);
21499                    let telemetry = project.client().telemetry().clone();
21500                    let is_via_ssh = project.is_via_remote_server();
21501                    (telemetry, is_via_ssh)
21502                };
21503                telemetry.log_edit_event("editor", is_via_ssh);
21504            }
21505            multi_buffer::Event::ExcerptsAdded {
21506                buffer,
21507                predecessor,
21508                excerpts,
21509            } => {
21510                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21511                let buffer_id = buffer.read(cx).remote_id();
21512                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21513                    && let Some(project) = &self.project
21514                {
21515                    update_uncommitted_diff_for_buffer(
21516                        cx.entity(),
21517                        project,
21518                        [buffer.clone()],
21519                        self.buffer.clone(),
21520                        cx,
21521                    )
21522                    .detach();
21523                }
21524                self.update_lsp_data(Some(buffer_id), window, cx);
21525                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21526                self.colorize_brackets(false, cx);
21527                cx.emit(EditorEvent::ExcerptsAdded {
21528                    buffer: buffer.clone(),
21529                    predecessor: *predecessor,
21530                    excerpts: excerpts.clone(),
21531                });
21532            }
21533            multi_buffer::Event::ExcerptsRemoved {
21534                ids,
21535                removed_buffer_ids,
21536            } => {
21537                if let Some(inlay_hints) = &mut self.inlay_hints {
21538                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21539                }
21540                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21541                for buffer_id in removed_buffer_ids {
21542                    self.registered_buffers.remove(buffer_id);
21543                }
21544                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21545                cx.emit(EditorEvent::ExcerptsRemoved {
21546                    ids: ids.clone(),
21547                    removed_buffer_ids: removed_buffer_ids.clone(),
21548                });
21549            }
21550            multi_buffer::Event::ExcerptsEdited {
21551                excerpt_ids,
21552                buffer_ids,
21553            } => {
21554                self.display_map.update(cx, |map, cx| {
21555                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21556                });
21557                cx.emit(EditorEvent::ExcerptsEdited {
21558                    ids: excerpt_ids.clone(),
21559                });
21560            }
21561            multi_buffer::Event::ExcerptsExpanded { ids } => {
21562                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21563                self.refresh_document_highlights(cx);
21564                for id in ids {
21565                    self.fetched_tree_sitter_chunks.remove(id);
21566                }
21567                self.colorize_brackets(false, cx);
21568                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21569            }
21570            multi_buffer::Event::Reparsed(buffer_id) => {
21571                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21572                self.refresh_selected_text_highlights(true, window, cx);
21573                self.colorize_brackets(true, cx);
21574                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21575
21576                cx.emit(EditorEvent::Reparsed(*buffer_id));
21577            }
21578            multi_buffer::Event::DiffHunksToggled => {
21579                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21580            }
21581            multi_buffer::Event::LanguageChanged(buffer_id) => {
21582                self.registered_buffers.remove(&buffer_id);
21583                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21584                cx.emit(EditorEvent::Reparsed(*buffer_id));
21585                cx.notify();
21586            }
21587            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21588            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21589            multi_buffer::Event::FileHandleChanged
21590            | multi_buffer::Event::Reloaded
21591            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21592            multi_buffer::Event::DiagnosticsUpdated => {
21593                self.update_diagnostics_state(window, cx);
21594            }
21595            _ => {}
21596        };
21597    }
21598
21599    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21600        if !self.diagnostics_enabled() {
21601            return;
21602        }
21603        self.refresh_active_diagnostics(cx);
21604        self.refresh_inline_diagnostics(true, window, cx);
21605        self.scrollbar_marker_state.dirty = true;
21606        cx.notify();
21607    }
21608
21609    pub fn start_temporary_diff_override(&mut self) {
21610        self.load_diff_task.take();
21611        self.temporary_diff_override = true;
21612    }
21613
21614    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21615        self.temporary_diff_override = false;
21616        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21617        self.buffer.update(cx, |buffer, cx| {
21618            buffer.set_all_diff_hunks_collapsed(cx);
21619        });
21620
21621        if let Some(project) = self.project.clone() {
21622            self.load_diff_task = Some(
21623                update_uncommitted_diff_for_buffer(
21624                    cx.entity(),
21625                    &project,
21626                    self.buffer.read(cx).all_buffers(),
21627                    self.buffer.clone(),
21628                    cx,
21629                )
21630                .shared(),
21631            );
21632        }
21633    }
21634
21635    fn on_display_map_changed(
21636        &mut self,
21637        _: Entity<DisplayMap>,
21638        _: &mut Window,
21639        cx: &mut Context<Self>,
21640    ) {
21641        cx.notify();
21642    }
21643
21644    fn fetch_accent_overrides(&self, cx: &App) -> Vec<SharedString> {
21645        if !self.mode.is_full() {
21646            return Vec::new();
21647        }
21648
21649        let theme_settings = theme::ThemeSettings::get_global(cx);
21650
21651        theme_settings
21652            .theme_overrides
21653            .get(cx.theme().name.as_ref())
21654            .map(|theme_style| &theme_style.accents)
21655            .into_iter()
21656            .flatten()
21657            .chain(
21658                theme_settings
21659                    .experimental_theme_overrides
21660                    .as_ref()
21661                    .map(|overrides| &overrides.accents)
21662                    .into_iter()
21663                    .flatten(),
21664            )
21665            .flat_map(|accent| accent.0.clone())
21666            .collect()
21667    }
21668
21669    fn fetch_applicable_language_settings(
21670        &self,
21671        cx: &App,
21672    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
21673        if !self.mode.is_full() {
21674            return HashMap::default();
21675        }
21676
21677        self.buffer().read(cx).all_buffers().into_iter().fold(
21678            HashMap::default(),
21679            |mut acc, buffer| {
21680                let buffer = buffer.read(cx);
21681                let language = buffer.language().map(|language| language.name());
21682                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
21683                    let file = buffer.file();
21684                    v.insert(language_settings(language, file, cx).into_owned());
21685                }
21686                acc
21687            },
21688        )
21689    }
21690
21691    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21692        let new_language_settings = self.fetch_applicable_language_settings(cx);
21693        let language_settings_changed = new_language_settings != self.applicable_language_settings;
21694        self.applicable_language_settings = new_language_settings;
21695
21696        let new_accent_overrides = self.fetch_accent_overrides(cx);
21697        let accent_overrides_changed = new_accent_overrides != self.accent_overrides;
21698        self.accent_overrides = new_accent_overrides;
21699
21700        if self.diagnostics_enabled() {
21701            let new_severity = EditorSettings::get_global(cx)
21702                .diagnostics_max_severity
21703                .unwrap_or(DiagnosticSeverity::Hint);
21704            self.set_max_diagnostics_severity(new_severity, cx);
21705        }
21706        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21707        self.update_edit_prediction_settings(cx);
21708        self.refresh_edit_prediction(true, false, window, cx);
21709        self.refresh_inline_values(cx);
21710        self.refresh_inlay_hints(
21711            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21712                self.selections.newest_anchor().head(),
21713                &self.buffer.read(cx).snapshot(cx),
21714                cx,
21715            )),
21716            cx,
21717        );
21718
21719        let old_cursor_shape = self.cursor_shape;
21720        let old_show_breadcrumbs = self.show_breadcrumbs;
21721
21722        {
21723            let editor_settings = EditorSettings::get_global(cx);
21724            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21725            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21726            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21727            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21728        }
21729
21730        if old_cursor_shape != self.cursor_shape {
21731            cx.emit(EditorEvent::CursorShapeChanged);
21732        }
21733
21734        if old_show_breadcrumbs != self.show_breadcrumbs {
21735            cx.emit(EditorEvent::BreadcrumbsChanged);
21736        }
21737
21738        let project_settings = ProjectSettings::get_global(cx);
21739        self.buffer_serialization = self
21740            .should_serialize_buffer()
21741            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21742
21743        if self.mode.is_full() {
21744            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21745            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21746            if self.show_inline_diagnostics != show_inline_diagnostics {
21747                self.show_inline_diagnostics = show_inline_diagnostics;
21748                self.refresh_inline_diagnostics(false, window, cx);
21749            }
21750
21751            if self.git_blame_inline_enabled != inline_blame_enabled {
21752                self.toggle_git_blame_inline_internal(false, window, cx);
21753            }
21754
21755            let minimap_settings = EditorSettings::get_global(cx).minimap;
21756            if self.minimap_visibility != MinimapVisibility::Disabled {
21757                if self.minimap_visibility.settings_visibility()
21758                    != minimap_settings.minimap_enabled()
21759                {
21760                    self.set_minimap_visibility(
21761                        MinimapVisibility::for_mode(self.mode(), cx),
21762                        window,
21763                        cx,
21764                    );
21765                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21766                    minimap_entity.update(cx, |minimap_editor, cx| {
21767                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21768                    })
21769                }
21770            }
21771
21772            if language_settings_changed || accent_overrides_changed {
21773                self.colorize_brackets(true, cx);
21774            }
21775
21776            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21777                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21778            }) {
21779                if !inlay_splice.is_empty() {
21780                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21781                }
21782                self.refresh_colors_for_visible_range(None, window, cx);
21783            }
21784        }
21785
21786        cx.notify();
21787    }
21788
21789    pub fn set_searchable(&mut self, searchable: bool) {
21790        self.searchable = searchable;
21791    }
21792
21793    pub fn searchable(&self) -> bool {
21794        self.searchable
21795    }
21796
21797    pub fn open_excerpts_in_split(
21798        &mut self,
21799        _: &OpenExcerptsSplit,
21800        window: &mut Window,
21801        cx: &mut Context<Self>,
21802    ) {
21803        self.open_excerpts_common(None, true, window, cx)
21804    }
21805
21806    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21807        self.open_excerpts_common(None, false, window, cx)
21808    }
21809
21810    fn open_excerpts_common(
21811        &mut self,
21812        jump_data: Option<JumpData>,
21813        split: bool,
21814        window: &mut Window,
21815        cx: &mut Context<Self>,
21816    ) {
21817        let Some(workspace) = self.workspace() else {
21818            cx.propagate();
21819            return;
21820        };
21821
21822        if self.buffer.read(cx).is_singleton() {
21823            cx.propagate();
21824            return;
21825        }
21826
21827        let mut new_selections_by_buffer = HashMap::default();
21828        match &jump_data {
21829            Some(JumpData::MultiBufferPoint {
21830                excerpt_id,
21831                position,
21832                anchor,
21833                line_offset_from_top,
21834            }) => {
21835                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21836                if let Some(buffer) = multi_buffer_snapshot
21837                    .buffer_id_for_excerpt(*excerpt_id)
21838                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21839                {
21840                    let buffer_snapshot = buffer.read(cx).snapshot();
21841                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21842                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21843                    } else {
21844                        buffer_snapshot.clip_point(*position, Bias::Left)
21845                    };
21846                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21847                    new_selections_by_buffer.insert(
21848                        buffer,
21849                        (
21850                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
21851                            Some(*line_offset_from_top),
21852                        ),
21853                    );
21854                }
21855            }
21856            Some(JumpData::MultiBufferRow {
21857                row,
21858                line_offset_from_top,
21859            }) => {
21860                let point = MultiBufferPoint::new(row.0, 0);
21861                if let Some((buffer, buffer_point, _)) =
21862                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21863                {
21864                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21865                    new_selections_by_buffer
21866                        .entry(buffer)
21867                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21868                        .0
21869                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
21870                }
21871            }
21872            None => {
21873                let selections = self
21874                    .selections
21875                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
21876                let multi_buffer = self.buffer.read(cx);
21877                for selection in selections {
21878                    for (snapshot, range, _, anchor) in multi_buffer
21879                        .snapshot(cx)
21880                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21881                    {
21882                        if let Some(anchor) = anchor {
21883                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21884                            else {
21885                                continue;
21886                            };
21887                            let offset = text::ToOffset::to_offset(
21888                                &anchor.text_anchor,
21889                                &buffer_handle.read(cx).snapshot(),
21890                            );
21891                            let range = BufferOffset(offset)..BufferOffset(offset);
21892                            new_selections_by_buffer
21893                                .entry(buffer_handle)
21894                                .or_insert((Vec::new(), None))
21895                                .0
21896                                .push(range)
21897                        } else {
21898                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21899                            else {
21900                                continue;
21901                            };
21902                            new_selections_by_buffer
21903                                .entry(buffer_handle)
21904                                .or_insert((Vec::new(), None))
21905                                .0
21906                                .push(range)
21907                        }
21908                    }
21909                }
21910            }
21911        }
21912
21913        new_selections_by_buffer
21914            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21915
21916        if new_selections_by_buffer.is_empty() {
21917            return;
21918        }
21919
21920        // We defer the pane interaction because we ourselves are a workspace item
21921        // and activating a new item causes the pane to call a method on us reentrantly,
21922        // which panics if we're on the stack.
21923        window.defer(cx, move |window, cx| {
21924            workspace.update(cx, |workspace, cx| {
21925                let pane = if split {
21926                    workspace.adjacent_pane(window, cx)
21927                } else {
21928                    workspace.active_pane().clone()
21929                };
21930
21931                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21932                    let editor = buffer
21933                        .read(cx)
21934                        .file()
21935                        .is_none()
21936                        .then(|| {
21937                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21938                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21939                            // Instead, we try to activate the existing editor in the pane first.
21940                            let (editor, pane_item_index) =
21941                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21942                                    let editor = item.downcast::<Editor>()?;
21943                                    let singleton_buffer =
21944                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21945                                    if singleton_buffer == buffer {
21946                                        Some((editor, i))
21947                                    } else {
21948                                        None
21949                                    }
21950                                })?;
21951                            pane.update(cx, |pane, cx| {
21952                                pane.activate_item(pane_item_index, true, true, window, cx)
21953                            });
21954                            Some(editor)
21955                        })
21956                        .flatten()
21957                        .unwrap_or_else(|| {
21958                            workspace.open_project_item::<Self>(
21959                                pane.clone(),
21960                                buffer,
21961                                true,
21962                                true,
21963                                window,
21964                                cx,
21965                            )
21966                        });
21967
21968                    editor.update(cx, |editor, cx| {
21969                        let autoscroll = match scroll_offset {
21970                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21971                            None => Autoscroll::newest(),
21972                        };
21973                        let nav_history = editor.nav_history.take();
21974                        editor.change_selections(
21975                            SelectionEffects::scroll(autoscroll),
21976                            window,
21977                            cx,
21978                            |s| {
21979                                s.select_ranges(ranges.into_iter().map(|range| {
21980                                    // we checked that the editor is a singleton editor so the offsets are valid
21981                                    MultiBufferOffset(range.start.0)..MultiBufferOffset(range.end.0)
21982                                }));
21983                            },
21984                        );
21985                        editor.nav_history = nav_history;
21986                    });
21987                }
21988            })
21989        });
21990    }
21991
21992    // For now, don't allow opening excerpts in buffers that aren't backed by
21993    // regular project files.
21994    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21995        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21996    }
21997
21998    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
21999        let snapshot = self.buffer.read(cx).read(cx);
22000        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22001        Some(
22002            ranges
22003                .iter()
22004                .map(move |range| {
22005                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22006                })
22007                .collect(),
22008        )
22009    }
22010
22011    fn selection_replacement_ranges(
22012        &self,
22013        range: Range<MultiBufferOffsetUtf16>,
22014        cx: &mut App,
22015    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22016        let selections = self
22017            .selections
22018            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22019        let newest_selection = selections
22020            .iter()
22021            .max_by_key(|selection| selection.id)
22022            .unwrap();
22023        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22024        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22025        let snapshot = self.buffer.read(cx).read(cx);
22026        selections
22027            .into_iter()
22028            .map(|mut selection| {
22029                selection.start.0.0 =
22030                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22031                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22032                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22033                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22034            })
22035            .collect()
22036    }
22037
22038    fn report_editor_event(
22039        &self,
22040        reported_event: ReportEditorEvent,
22041        file_extension: Option<String>,
22042        cx: &App,
22043    ) {
22044        if cfg!(any(test, feature = "test-support")) {
22045            return;
22046        }
22047
22048        let Some(project) = &self.project else { return };
22049
22050        // If None, we are in a file without an extension
22051        let file = self
22052            .buffer
22053            .read(cx)
22054            .as_singleton()
22055            .and_then(|b| b.read(cx).file());
22056        let file_extension = file_extension.or(file
22057            .as_ref()
22058            .and_then(|file| Path::new(file.file_name(cx)).extension())
22059            .and_then(|e| e.to_str())
22060            .map(|a| a.to_string()));
22061
22062        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22063            .map(|vim_mode| vim_mode.0)
22064            .unwrap_or(false);
22065
22066        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22067        let copilot_enabled = edit_predictions_provider
22068            == language::language_settings::EditPredictionProvider::Copilot;
22069        let copilot_enabled_for_language = self
22070            .buffer
22071            .read(cx)
22072            .language_settings(cx)
22073            .show_edit_predictions;
22074
22075        let project = project.read(cx);
22076        let event_type = reported_event.event_type();
22077
22078        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22079            telemetry::event!(
22080                event_type,
22081                type = if auto_saved {"autosave"} else {"manual"},
22082                file_extension,
22083                vim_mode,
22084                copilot_enabled,
22085                copilot_enabled_for_language,
22086                edit_predictions_provider,
22087                is_via_ssh = project.is_via_remote_server(),
22088            );
22089        } else {
22090            telemetry::event!(
22091                event_type,
22092                file_extension,
22093                vim_mode,
22094                copilot_enabled,
22095                copilot_enabled_for_language,
22096                edit_predictions_provider,
22097                is_via_ssh = project.is_via_remote_server(),
22098            );
22099        };
22100    }
22101
22102    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22103    /// with each line being an array of {text, highlight} objects.
22104    fn copy_highlight_json(
22105        &mut self,
22106        _: &CopyHighlightJson,
22107        window: &mut Window,
22108        cx: &mut Context<Self>,
22109    ) {
22110        #[derive(Serialize)]
22111        struct Chunk<'a> {
22112            text: String,
22113            highlight: Option<&'a str>,
22114        }
22115
22116        let snapshot = self.buffer.read(cx).snapshot(cx);
22117        let range = self
22118            .selected_text_range(false, window, cx)
22119            .and_then(|selection| {
22120                if selection.range.is_empty() {
22121                    None
22122                } else {
22123                    Some(
22124                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22125                            selection.range.start,
22126                        )))
22127                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22128                                selection.range.end,
22129                            ))),
22130                    )
22131                }
22132            })
22133            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22134
22135        let chunks = snapshot.chunks(range, true);
22136        let mut lines = Vec::new();
22137        let mut line: VecDeque<Chunk> = VecDeque::new();
22138
22139        let Some(style) = self.style.as_ref() else {
22140            return;
22141        };
22142
22143        for chunk in chunks {
22144            let highlight = chunk
22145                .syntax_highlight_id
22146                .and_then(|id| id.name(&style.syntax));
22147            let mut chunk_lines = chunk.text.split('\n').peekable();
22148            while let Some(text) = chunk_lines.next() {
22149                let mut merged_with_last_token = false;
22150                if let Some(last_token) = line.back_mut()
22151                    && last_token.highlight == highlight
22152                {
22153                    last_token.text.push_str(text);
22154                    merged_with_last_token = true;
22155                }
22156
22157                if !merged_with_last_token {
22158                    line.push_back(Chunk {
22159                        text: text.into(),
22160                        highlight,
22161                    });
22162                }
22163
22164                if chunk_lines.peek().is_some() {
22165                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22166                        line.pop_front();
22167                    }
22168                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22169                        line.pop_back();
22170                    }
22171
22172                    lines.push(mem::take(&mut line));
22173                }
22174            }
22175        }
22176
22177        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22178            return;
22179        };
22180        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22181    }
22182
22183    pub fn open_context_menu(
22184        &mut self,
22185        _: &OpenContextMenu,
22186        window: &mut Window,
22187        cx: &mut Context<Self>,
22188    ) {
22189        self.request_autoscroll(Autoscroll::newest(), cx);
22190        let position = self
22191            .selections
22192            .newest_display(&self.display_snapshot(cx))
22193            .start;
22194        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22195    }
22196
22197    pub fn replay_insert_event(
22198        &mut self,
22199        text: &str,
22200        relative_utf16_range: Option<Range<isize>>,
22201        window: &mut Window,
22202        cx: &mut Context<Self>,
22203    ) {
22204        if !self.input_enabled {
22205            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22206            return;
22207        }
22208        if let Some(relative_utf16_range) = relative_utf16_range {
22209            let selections = self
22210                .selections
22211                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22212            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22213                let new_ranges = selections.into_iter().map(|range| {
22214                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22215                        range
22216                            .head()
22217                            .0
22218                            .0
22219                            .saturating_add_signed(relative_utf16_range.start),
22220                    ));
22221                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22222                        range
22223                            .head()
22224                            .0
22225                            .0
22226                            .saturating_add_signed(relative_utf16_range.end),
22227                    ));
22228                    start..end
22229                });
22230                s.select_ranges(new_ranges);
22231            });
22232        }
22233
22234        self.handle_input(text, window, cx);
22235    }
22236
22237    pub fn is_focused(&self, window: &Window) -> bool {
22238        self.focus_handle.is_focused(window)
22239    }
22240
22241    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22242        cx.emit(EditorEvent::Focused);
22243
22244        if let Some(descendant) = self
22245            .last_focused_descendant
22246            .take()
22247            .and_then(|descendant| descendant.upgrade())
22248        {
22249            window.focus(&descendant);
22250        } else {
22251            if let Some(blame) = self.blame.as_ref() {
22252                blame.update(cx, GitBlame::focus)
22253            }
22254
22255            self.blink_manager.update(cx, BlinkManager::enable);
22256            self.show_cursor_names(window, cx);
22257            self.buffer.update(cx, |buffer, cx| {
22258                buffer.finalize_last_transaction(cx);
22259                if self.leader_id.is_none() {
22260                    buffer.set_active_selections(
22261                        &self.selections.disjoint_anchors_arc(),
22262                        self.selections.line_mode(),
22263                        self.cursor_shape,
22264                        cx,
22265                    );
22266                }
22267            });
22268
22269            if let Some(position_map) = self.last_position_map.clone() {
22270                EditorElement::mouse_moved(
22271                    self,
22272                    &MouseMoveEvent {
22273                        position: window.mouse_position(),
22274                        pressed_button: None,
22275                        modifiers: window.modifiers(),
22276                    },
22277                    &position_map,
22278                    window,
22279                    cx,
22280                );
22281            }
22282        }
22283    }
22284
22285    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22286        cx.emit(EditorEvent::FocusedIn)
22287    }
22288
22289    fn handle_focus_out(
22290        &mut self,
22291        event: FocusOutEvent,
22292        _window: &mut Window,
22293        cx: &mut Context<Self>,
22294    ) {
22295        if event.blurred != self.focus_handle {
22296            self.last_focused_descendant = Some(event.blurred);
22297        }
22298        self.selection_drag_state = SelectionDragState::None;
22299        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22300    }
22301
22302    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22303        self.blink_manager.update(cx, BlinkManager::disable);
22304        self.buffer
22305            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22306
22307        if let Some(blame) = self.blame.as_ref() {
22308            blame.update(cx, GitBlame::blur)
22309        }
22310        if !self.hover_state.focused(window, cx) {
22311            hide_hover(self, cx);
22312        }
22313        if !self
22314            .context_menu
22315            .borrow()
22316            .as_ref()
22317            .is_some_and(|context_menu| context_menu.focused(window, cx))
22318        {
22319            self.hide_context_menu(window, cx);
22320        }
22321        self.take_active_edit_prediction(cx);
22322        cx.emit(EditorEvent::Blurred);
22323        cx.notify();
22324    }
22325
22326    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22327        let mut pending: String = window
22328            .pending_input_keystrokes()
22329            .into_iter()
22330            .flatten()
22331            .filter_map(|keystroke| keystroke.key_char.clone())
22332            .collect();
22333
22334        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22335            pending = "".to_string();
22336        }
22337
22338        let existing_pending = self
22339            .text_highlights::<PendingInput>(cx)
22340            .map(|(_, ranges)| ranges.to_vec());
22341        if existing_pending.is_none() && pending.is_empty() {
22342            return;
22343        }
22344        let transaction =
22345            self.transact(window, cx, |this, window, cx| {
22346                let selections = this
22347                    .selections
22348                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22349                let edits = selections
22350                    .iter()
22351                    .map(|selection| (selection.end..selection.end, pending.clone()));
22352                this.edit(edits, cx);
22353                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22354                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22355                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22356                    }));
22357                });
22358                if let Some(existing_ranges) = existing_pending {
22359                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22360                    this.edit(edits, cx);
22361                }
22362            });
22363
22364        let snapshot = self.snapshot(window, cx);
22365        let ranges = self
22366            .selections
22367            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22368            .into_iter()
22369            .map(|selection| {
22370                snapshot.buffer_snapshot().anchor_after(selection.end)
22371                    ..snapshot
22372                        .buffer_snapshot()
22373                        .anchor_before(selection.end + pending.len())
22374            })
22375            .collect();
22376
22377        if pending.is_empty() {
22378            self.clear_highlights::<PendingInput>(cx);
22379        } else {
22380            self.highlight_text::<PendingInput>(
22381                ranges,
22382                HighlightStyle {
22383                    underline: Some(UnderlineStyle {
22384                        thickness: px(1.),
22385                        color: None,
22386                        wavy: false,
22387                    }),
22388                    ..Default::default()
22389                },
22390                cx,
22391            );
22392        }
22393
22394        self.ime_transaction = self.ime_transaction.or(transaction);
22395        if let Some(transaction) = self.ime_transaction {
22396            self.buffer.update(cx, |buffer, cx| {
22397                buffer.group_until_transaction(transaction, cx);
22398            });
22399        }
22400
22401        if self.text_highlights::<PendingInput>(cx).is_none() {
22402            self.ime_transaction.take();
22403        }
22404    }
22405
22406    pub fn register_action_renderer(
22407        &mut self,
22408        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22409    ) -> Subscription {
22410        let id = self.next_editor_action_id.post_inc();
22411        self.editor_actions
22412            .borrow_mut()
22413            .insert(id, Box::new(listener));
22414
22415        let editor_actions = self.editor_actions.clone();
22416        Subscription::new(move || {
22417            editor_actions.borrow_mut().remove(&id);
22418        })
22419    }
22420
22421    pub fn register_action<A: Action>(
22422        &mut self,
22423        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22424    ) -> Subscription {
22425        let id = self.next_editor_action_id.post_inc();
22426        let listener = Arc::new(listener);
22427        self.editor_actions.borrow_mut().insert(
22428            id,
22429            Box::new(move |_, window, _| {
22430                let listener = listener.clone();
22431                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22432                    let action = action.downcast_ref().unwrap();
22433                    if phase == DispatchPhase::Bubble {
22434                        listener(action, window, cx)
22435                    }
22436                })
22437            }),
22438        );
22439
22440        let editor_actions = self.editor_actions.clone();
22441        Subscription::new(move || {
22442            editor_actions.borrow_mut().remove(&id);
22443        })
22444    }
22445
22446    pub fn file_header_size(&self) -> u32 {
22447        FILE_HEADER_HEIGHT
22448    }
22449
22450    pub fn restore(
22451        &mut self,
22452        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22453        window: &mut Window,
22454        cx: &mut Context<Self>,
22455    ) {
22456        let workspace = self.workspace();
22457        let project = self.project();
22458        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22459            let mut tasks = Vec::new();
22460            for (buffer_id, changes) in revert_changes {
22461                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22462                    buffer.update(cx, |buffer, cx| {
22463                        buffer.edit(
22464                            changes
22465                                .into_iter()
22466                                .map(|(range, text)| (range, text.to_string())),
22467                            None,
22468                            cx,
22469                        );
22470                    });
22471
22472                    if let Some(project) =
22473                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22474                    {
22475                        project.update(cx, |project, cx| {
22476                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22477                        })
22478                    }
22479                }
22480            }
22481            tasks
22482        });
22483        cx.spawn_in(window, async move |_, cx| {
22484            for (buffer, task) in save_tasks {
22485                let result = task.await;
22486                if result.is_err() {
22487                    let Some(path) = buffer
22488                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22489                        .ok()
22490                    else {
22491                        continue;
22492                    };
22493                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22494                        let Some(task) = cx
22495                            .update_window_entity(workspace, |workspace, window, cx| {
22496                                workspace
22497                                    .open_path_preview(path, None, false, false, false, window, cx)
22498                            })
22499                            .ok()
22500                        else {
22501                            continue;
22502                        };
22503                        task.await.log_err();
22504                    }
22505                }
22506            }
22507        })
22508        .detach();
22509        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22510            selections.refresh()
22511        });
22512    }
22513
22514    pub fn to_pixel_point(
22515        &self,
22516        source: multi_buffer::Anchor,
22517        editor_snapshot: &EditorSnapshot,
22518        window: &mut Window,
22519    ) -> Option<gpui::Point<Pixels>> {
22520        let source_point = source.to_display_point(editor_snapshot);
22521        self.display_to_pixel_point(source_point, editor_snapshot, window)
22522    }
22523
22524    pub fn display_to_pixel_point(
22525        &self,
22526        source: DisplayPoint,
22527        editor_snapshot: &EditorSnapshot,
22528        window: &mut Window,
22529    ) -> Option<gpui::Point<Pixels>> {
22530        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22531        let text_layout_details = self.text_layout_details(window);
22532        let scroll_top = text_layout_details
22533            .scroll_anchor
22534            .scroll_position(editor_snapshot)
22535            .y;
22536
22537        if source.row().as_f64() < scroll_top.floor() {
22538            return None;
22539        }
22540        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22541        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22542        Some(gpui::Point::new(source_x, source_y))
22543    }
22544
22545    pub fn has_visible_completions_menu(&self) -> bool {
22546        !self.edit_prediction_preview_is_active()
22547            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22548                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22549            })
22550    }
22551
22552    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22553        if self.mode.is_minimap() {
22554            return;
22555        }
22556        self.addons
22557            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22558    }
22559
22560    pub fn unregister_addon<T: Addon>(&mut self) {
22561        self.addons.remove(&std::any::TypeId::of::<T>());
22562    }
22563
22564    pub fn addon<T: Addon>(&self) -> Option<&T> {
22565        let type_id = std::any::TypeId::of::<T>();
22566        self.addons
22567            .get(&type_id)
22568            .and_then(|item| item.to_any().downcast_ref::<T>())
22569    }
22570
22571    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22572        let type_id = std::any::TypeId::of::<T>();
22573        self.addons
22574            .get_mut(&type_id)
22575            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22576    }
22577
22578    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22579        let text_layout_details = self.text_layout_details(window);
22580        let style = &text_layout_details.editor_style;
22581        let font_id = window.text_system().resolve_font(&style.text.font());
22582        let font_size = style.text.font_size.to_pixels(window.rem_size());
22583        let line_height = style.text.line_height_in_pixels(window.rem_size());
22584        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22585        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22586
22587        CharacterDimensions {
22588            em_width,
22589            em_advance,
22590            line_height,
22591        }
22592    }
22593
22594    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22595        self.load_diff_task.clone()
22596    }
22597
22598    fn read_metadata_from_db(
22599        &mut self,
22600        item_id: u64,
22601        workspace_id: WorkspaceId,
22602        window: &mut Window,
22603        cx: &mut Context<Editor>,
22604    ) {
22605        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22606            && !self.mode.is_minimap()
22607            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22608        {
22609            let buffer_snapshot = OnceCell::new();
22610
22611            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22612                && !folds.is_empty()
22613            {
22614                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22615                self.fold_ranges(
22616                    folds
22617                        .into_iter()
22618                        .map(|(start, end)| {
22619                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22620                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22621                        })
22622                        .collect(),
22623                    false,
22624                    window,
22625                    cx,
22626                );
22627            }
22628
22629            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22630                && !selections.is_empty()
22631            {
22632                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22633                // skip adding the initial selection to selection history
22634                self.selection_history.mode = SelectionHistoryMode::Skipping;
22635                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22636                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22637                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22638                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22639                    }));
22640                });
22641                self.selection_history.mode = SelectionHistoryMode::Normal;
22642            };
22643        }
22644
22645        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22646    }
22647
22648    fn update_lsp_data(
22649        &mut self,
22650        for_buffer: Option<BufferId>,
22651        window: &mut Window,
22652        cx: &mut Context<'_, Self>,
22653    ) {
22654        self.pull_diagnostics(for_buffer, window, cx);
22655        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22656    }
22657
22658    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22659        if self.ignore_lsp_data() {
22660            return;
22661        }
22662        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
22663            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22664        }
22665    }
22666
22667    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22668        if self.ignore_lsp_data() {
22669            return;
22670        }
22671
22672        if !self.registered_buffers.contains_key(&buffer_id)
22673            && let Some(project) = self.project.as_ref()
22674        {
22675            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22676                project.update(cx, |project, cx| {
22677                    self.registered_buffers.insert(
22678                        buffer_id,
22679                        project.register_buffer_with_language_servers(&buffer, cx),
22680                    );
22681                });
22682            } else {
22683                self.registered_buffers.remove(&buffer_id);
22684            }
22685        }
22686    }
22687
22688    fn ignore_lsp_data(&self) -> bool {
22689        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22690        // skip any LSP updates for it.
22691        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22692    }
22693}
22694
22695fn edit_for_markdown_paste<'a>(
22696    buffer: &MultiBufferSnapshot,
22697    range: Range<MultiBufferOffset>,
22698    to_insert: &'a str,
22699    url: Option<url::Url>,
22700) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
22701    if url.is_none() {
22702        return (range, Cow::Borrowed(to_insert));
22703    };
22704
22705    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22706
22707    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22708        Cow::Borrowed(to_insert)
22709    } else {
22710        Cow::Owned(format!("[{old_text}]({to_insert})"))
22711    };
22712    (range, new_text)
22713}
22714
22715fn process_completion_for_edit(
22716    completion: &Completion,
22717    intent: CompletionIntent,
22718    buffer: &Entity<Buffer>,
22719    cursor_position: &text::Anchor,
22720    cx: &mut Context<Editor>,
22721) -> CompletionEdit {
22722    let buffer = buffer.read(cx);
22723    let buffer_snapshot = buffer.snapshot();
22724    let (snippet, new_text) = if completion.is_snippet() {
22725        let mut snippet_source = completion.new_text.clone();
22726        // Workaround for typescript language server issues so that methods don't expand within
22727        // strings and functions with type expressions. The previous point is used because the query
22728        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22729        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22730        let previous_point = if previous_point.column > 0 {
22731            cursor_position.to_previous_offset(&buffer_snapshot)
22732        } else {
22733            cursor_position.to_offset(&buffer_snapshot)
22734        };
22735        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22736            && scope.prefers_label_for_snippet_in_completion()
22737            && let Some(label) = completion.label()
22738            && matches!(
22739                completion.kind(),
22740                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22741            )
22742        {
22743            snippet_source = label;
22744        }
22745        match Snippet::parse(&snippet_source).log_err() {
22746            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22747            None => (None, completion.new_text.clone()),
22748        }
22749    } else {
22750        (None, completion.new_text.clone())
22751    };
22752
22753    let mut range_to_replace = {
22754        let replace_range = &completion.replace_range;
22755        if let CompletionSource::Lsp {
22756            insert_range: Some(insert_range),
22757            ..
22758        } = &completion.source
22759        {
22760            debug_assert_eq!(
22761                insert_range.start, replace_range.start,
22762                "insert_range and replace_range should start at the same position"
22763            );
22764            debug_assert!(
22765                insert_range
22766                    .start
22767                    .cmp(cursor_position, &buffer_snapshot)
22768                    .is_le(),
22769                "insert_range should start before or at cursor position"
22770            );
22771            debug_assert!(
22772                replace_range
22773                    .start
22774                    .cmp(cursor_position, &buffer_snapshot)
22775                    .is_le(),
22776                "replace_range should start before or at cursor position"
22777            );
22778
22779            let should_replace = match intent {
22780                CompletionIntent::CompleteWithInsert => false,
22781                CompletionIntent::CompleteWithReplace => true,
22782                CompletionIntent::Complete | CompletionIntent::Compose => {
22783                    let insert_mode =
22784                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22785                            .completions
22786                            .lsp_insert_mode;
22787                    match insert_mode {
22788                        LspInsertMode::Insert => false,
22789                        LspInsertMode::Replace => true,
22790                        LspInsertMode::ReplaceSubsequence => {
22791                            let mut text_to_replace = buffer.chars_for_range(
22792                                buffer.anchor_before(replace_range.start)
22793                                    ..buffer.anchor_after(replace_range.end),
22794                            );
22795                            let mut current_needle = text_to_replace.next();
22796                            for haystack_ch in completion.label.text.chars() {
22797                                if let Some(needle_ch) = current_needle
22798                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22799                                {
22800                                    current_needle = text_to_replace.next();
22801                                }
22802                            }
22803                            current_needle.is_none()
22804                        }
22805                        LspInsertMode::ReplaceSuffix => {
22806                            if replace_range
22807                                .end
22808                                .cmp(cursor_position, &buffer_snapshot)
22809                                .is_gt()
22810                            {
22811                                let range_after_cursor = *cursor_position..replace_range.end;
22812                                let text_after_cursor = buffer
22813                                    .text_for_range(
22814                                        buffer.anchor_before(range_after_cursor.start)
22815                                            ..buffer.anchor_after(range_after_cursor.end),
22816                                    )
22817                                    .collect::<String>()
22818                                    .to_ascii_lowercase();
22819                                completion
22820                                    .label
22821                                    .text
22822                                    .to_ascii_lowercase()
22823                                    .ends_with(&text_after_cursor)
22824                            } else {
22825                                true
22826                            }
22827                        }
22828                    }
22829                }
22830            };
22831
22832            if should_replace {
22833                replace_range.clone()
22834            } else {
22835                insert_range.clone()
22836            }
22837        } else {
22838            replace_range.clone()
22839        }
22840    };
22841
22842    if range_to_replace
22843        .end
22844        .cmp(cursor_position, &buffer_snapshot)
22845        .is_lt()
22846    {
22847        range_to_replace.end = *cursor_position;
22848    }
22849
22850    let replace_range = range_to_replace.to_offset(buffer);
22851    CompletionEdit {
22852        new_text,
22853        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
22854        snippet,
22855    }
22856}
22857
22858struct CompletionEdit {
22859    new_text: String,
22860    replace_range: Range<BufferOffset>,
22861    snippet: Option<Snippet>,
22862}
22863
22864fn insert_extra_newline_brackets(
22865    buffer: &MultiBufferSnapshot,
22866    range: Range<MultiBufferOffset>,
22867    language: &language::LanguageScope,
22868) -> bool {
22869    let leading_whitespace_len = buffer
22870        .reversed_chars_at(range.start)
22871        .take_while(|c| c.is_whitespace() && *c != '\n')
22872        .map(|c| c.len_utf8())
22873        .sum::<usize>();
22874    let trailing_whitespace_len = buffer
22875        .chars_at(range.end)
22876        .take_while(|c| c.is_whitespace() && *c != '\n')
22877        .map(|c| c.len_utf8())
22878        .sum::<usize>();
22879    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22880
22881    language.brackets().any(|(pair, enabled)| {
22882        let pair_start = pair.start.trim_end();
22883        let pair_end = pair.end.trim_start();
22884
22885        enabled
22886            && pair.newline
22887            && buffer.contains_str_at(range.end, pair_end)
22888            && buffer.contains_str_at(
22889                range.start.saturating_sub_usize(pair_start.len()),
22890                pair_start,
22891            )
22892    })
22893}
22894
22895fn insert_extra_newline_tree_sitter(
22896    buffer: &MultiBufferSnapshot,
22897    range: Range<MultiBufferOffset>,
22898) -> bool {
22899    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22900        [(buffer, range, _)] => (*buffer, range.clone()),
22901        _ => return false,
22902    };
22903    let pair = {
22904        let mut result: Option<BracketMatch<usize>> = None;
22905
22906        for pair in buffer
22907            .all_bracket_ranges(range.start.0..range.end.0)
22908            .filter(move |pair| {
22909                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
22910            })
22911        {
22912            let len = pair.close_range.end - pair.open_range.start;
22913
22914            if let Some(existing) = &result {
22915                let existing_len = existing.close_range.end - existing.open_range.start;
22916                if len > existing_len {
22917                    continue;
22918                }
22919            }
22920
22921            result = Some(pair);
22922        }
22923
22924        result
22925    };
22926    let Some(pair) = pair else {
22927        return false;
22928    };
22929    pair.newline_only
22930        && buffer
22931            .chars_for_range(pair.open_range.end..range.start.0)
22932            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
22933            .all(|c| c.is_whitespace() && c != '\n')
22934}
22935
22936fn update_uncommitted_diff_for_buffer(
22937    editor: Entity<Editor>,
22938    project: &Entity<Project>,
22939    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22940    buffer: Entity<MultiBuffer>,
22941    cx: &mut App,
22942) -> Task<()> {
22943    let mut tasks = Vec::new();
22944    project.update(cx, |project, cx| {
22945        for buffer in buffers {
22946            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22947                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22948            }
22949        }
22950    });
22951    cx.spawn(async move |cx| {
22952        let diffs = future::join_all(tasks).await;
22953        if editor
22954            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22955            .unwrap_or(false)
22956        {
22957            return;
22958        }
22959
22960        buffer
22961            .update(cx, |buffer, cx| {
22962                for diff in diffs.into_iter().flatten() {
22963                    buffer.add_diff(diff, cx);
22964                }
22965            })
22966            .ok();
22967    })
22968}
22969
22970fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22971    let tab_size = tab_size.get() as usize;
22972    let mut width = offset;
22973
22974    for ch in text.chars() {
22975        width += if ch == '\t' {
22976            tab_size - (width % tab_size)
22977        } else {
22978            1
22979        };
22980    }
22981
22982    width - offset
22983}
22984
22985#[cfg(test)]
22986mod tests {
22987    use super::*;
22988
22989    #[test]
22990    fn test_string_size_with_expanded_tabs() {
22991        let nz = |val| NonZeroU32::new(val).unwrap();
22992        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22993        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22994        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22995        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22996        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22997        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22998        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22999        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23000    }
23001}
23002
23003/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23004struct WordBreakingTokenizer<'a> {
23005    input: &'a str,
23006}
23007
23008impl<'a> WordBreakingTokenizer<'a> {
23009    fn new(input: &'a str) -> Self {
23010        Self { input }
23011    }
23012}
23013
23014fn is_char_ideographic(ch: char) -> bool {
23015    use unicode_script::Script::*;
23016    use unicode_script::UnicodeScript;
23017    matches!(ch.script(), Han | Tangut | Yi)
23018}
23019
23020fn is_grapheme_ideographic(text: &str) -> bool {
23021    text.chars().any(is_char_ideographic)
23022}
23023
23024fn is_grapheme_whitespace(text: &str) -> bool {
23025    text.chars().any(|x| x.is_whitespace())
23026}
23027
23028fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23029    text.chars()
23030        .next()
23031        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23032}
23033
23034#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23035enum WordBreakToken<'a> {
23036    Word { token: &'a str, grapheme_len: usize },
23037    InlineWhitespace { token: &'a str, grapheme_len: usize },
23038    Newline,
23039}
23040
23041impl<'a> Iterator for WordBreakingTokenizer<'a> {
23042    /// Yields a span, the count of graphemes in the token, and whether it was
23043    /// whitespace. Note that it also breaks at word boundaries.
23044    type Item = WordBreakToken<'a>;
23045
23046    fn next(&mut self) -> Option<Self::Item> {
23047        use unicode_segmentation::UnicodeSegmentation;
23048        if self.input.is_empty() {
23049            return None;
23050        }
23051
23052        let mut iter = self.input.graphemes(true).peekable();
23053        let mut offset = 0;
23054        let mut grapheme_len = 0;
23055        if let Some(first_grapheme) = iter.next() {
23056            let is_newline = first_grapheme == "\n";
23057            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23058            offset += first_grapheme.len();
23059            grapheme_len += 1;
23060            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23061                if let Some(grapheme) = iter.peek().copied()
23062                    && should_stay_with_preceding_ideograph(grapheme)
23063                {
23064                    offset += grapheme.len();
23065                    grapheme_len += 1;
23066                }
23067            } else {
23068                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23069                let mut next_word_bound = words.peek().copied();
23070                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23071                    next_word_bound = words.next();
23072                }
23073                while let Some(grapheme) = iter.peek().copied() {
23074                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23075                        break;
23076                    };
23077                    if is_grapheme_whitespace(grapheme) != is_whitespace
23078                        || (grapheme == "\n") != is_newline
23079                    {
23080                        break;
23081                    };
23082                    offset += grapheme.len();
23083                    grapheme_len += 1;
23084                    iter.next();
23085                }
23086            }
23087            let token = &self.input[..offset];
23088            self.input = &self.input[offset..];
23089            if token == "\n" {
23090                Some(WordBreakToken::Newline)
23091            } else if is_whitespace {
23092                Some(WordBreakToken::InlineWhitespace {
23093                    token,
23094                    grapheme_len,
23095                })
23096            } else {
23097                Some(WordBreakToken::Word {
23098                    token,
23099                    grapheme_len,
23100                })
23101            }
23102        } else {
23103            None
23104        }
23105    }
23106}
23107
23108#[test]
23109fn test_word_breaking_tokenizer() {
23110    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23111        ("", &[]),
23112        ("  ", &[whitespace("  ", 2)]),
23113        ("Ʒ", &[word("Ʒ", 1)]),
23114        ("Ǽ", &[word("Ǽ", 1)]),
23115        ("", &[word("", 1)]),
23116        ("⋑⋑", &[word("⋑⋑", 2)]),
23117        (
23118            "原理,进而",
23119            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23120        ),
23121        (
23122            "hello world",
23123            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23124        ),
23125        (
23126            "hello, world",
23127            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23128        ),
23129        (
23130            "  hello world",
23131            &[
23132                whitespace("  ", 2),
23133                word("hello", 5),
23134                whitespace(" ", 1),
23135                word("world", 5),
23136            ],
23137        ),
23138        (
23139            "这是什么 \n 钢笔",
23140            &[
23141                word("", 1),
23142                word("", 1),
23143                word("", 1),
23144                word("", 1),
23145                whitespace(" ", 1),
23146                newline(),
23147                whitespace(" ", 1),
23148                word("", 1),
23149                word("", 1),
23150            ],
23151        ),
23152        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23153    ];
23154
23155    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23156        WordBreakToken::Word {
23157            token,
23158            grapheme_len,
23159        }
23160    }
23161
23162    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23163        WordBreakToken::InlineWhitespace {
23164            token,
23165            grapheme_len,
23166        }
23167    }
23168
23169    fn newline() -> WordBreakToken<'static> {
23170        WordBreakToken::Newline
23171    }
23172
23173    for (input, result) in tests {
23174        assert_eq!(
23175            WordBreakingTokenizer::new(input)
23176                .collect::<Vec<_>>()
23177                .as_slice(),
23178            *result,
23179        );
23180    }
23181}
23182
23183fn wrap_with_prefix(
23184    first_line_prefix: String,
23185    subsequent_lines_prefix: String,
23186    unwrapped_text: String,
23187    wrap_column: usize,
23188    tab_size: NonZeroU32,
23189    preserve_existing_whitespace: bool,
23190) -> String {
23191    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23192    let subsequent_lines_prefix_len =
23193        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23194    let mut wrapped_text = String::new();
23195    let mut current_line = first_line_prefix;
23196    let mut is_first_line = true;
23197
23198    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23199    let mut current_line_len = first_line_prefix_len;
23200    let mut in_whitespace = false;
23201    for token in tokenizer {
23202        let have_preceding_whitespace = in_whitespace;
23203        match token {
23204            WordBreakToken::Word {
23205                token,
23206                grapheme_len,
23207            } => {
23208                in_whitespace = false;
23209                let current_prefix_len = if is_first_line {
23210                    first_line_prefix_len
23211                } else {
23212                    subsequent_lines_prefix_len
23213                };
23214                if current_line_len + grapheme_len > wrap_column
23215                    && current_line_len != current_prefix_len
23216                {
23217                    wrapped_text.push_str(current_line.trim_end());
23218                    wrapped_text.push('\n');
23219                    is_first_line = false;
23220                    current_line = subsequent_lines_prefix.clone();
23221                    current_line_len = subsequent_lines_prefix_len;
23222                }
23223                current_line.push_str(token);
23224                current_line_len += grapheme_len;
23225            }
23226            WordBreakToken::InlineWhitespace {
23227                mut token,
23228                mut grapheme_len,
23229            } => {
23230                in_whitespace = true;
23231                if have_preceding_whitespace && !preserve_existing_whitespace {
23232                    continue;
23233                }
23234                if !preserve_existing_whitespace {
23235                    // Keep a single whitespace grapheme as-is
23236                    if let Some(first) =
23237                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23238                    {
23239                        token = first;
23240                    } else {
23241                        token = " ";
23242                    }
23243                    grapheme_len = 1;
23244                }
23245                let current_prefix_len = if is_first_line {
23246                    first_line_prefix_len
23247                } else {
23248                    subsequent_lines_prefix_len
23249                };
23250                if current_line_len + grapheme_len > wrap_column {
23251                    wrapped_text.push_str(current_line.trim_end());
23252                    wrapped_text.push('\n');
23253                    is_first_line = false;
23254                    current_line = subsequent_lines_prefix.clone();
23255                    current_line_len = subsequent_lines_prefix_len;
23256                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23257                    current_line.push_str(token);
23258                    current_line_len += grapheme_len;
23259                }
23260            }
23261            WordBreakToken::Newline => {
23262                in_whitespace = true;
23263                let current_prefix_len = if is_first_line {
23264                    first_line_prefix_len
23265                } else {
23266                    subsequent_lines_prefix_len
23267                };
23268                if preserve_existing_whitespace {
23269                    wrapped_text.push_str(current_line.trim_end());
23270                    wrapped_text.push('\n');
23271                    is_first_line = false;
23272                    current_line = subsequent_lines_prefix.clone();
23273                    current_line_len = subsequent_lines_prefix_len;
23274                } else if have_preceding_whitespace {
23275                    continue;
23276                } else if current_line_len + 1 > wrap_column
23277                    && current_line_len != current_prefix_len
23278                {
23279                    wrapped_text.push_str(current_line.trim_end());
23280                    wrapped_text.push('\n');
23281                    is_first_line = false;
23282                    current_line = subsequent_lines_prefix.clone();
23283                    current_line_len = subsequent_lines_prefix_len;
23284                } else if current_line_len != current_prefix_len {
23285                    current_line.push(' ');
23286                    current_line_len += 1;
23287                }
23288            }
23289        }
23290    }
23291
23292    if !current_line.is_empty() {
23293        wrapped_text.push_str(&current_line);
23294    }
23295    wrapped_text
23296}
23297
23298#[test]
23299fn test_wrap_with_prefix() {
23300    assert_eq!(
23301        wrap_with_prefix(
23302            "# ".to_string(),
23303            "# ".to_string(),
23304            "abcdefg".to_string(),
23305            4,
23306            NonZeroU32::new(4).unwrap(),
23307            false,
23308        ),
23309        "# abcdefg"
23310    );
23311    assert_eq!(
23312        wrap_with_prefix(
23313            "".to_string(),
23314            "".to_string(),
23315            "\thello world".to_string(),
23316            8,
23317            NonZeroU32::new(4).unwrap(),
23318            false,
23319        ),
23320        "hello\nworld"
23321    );
23322    assert_eq!(
23323        wrap_with_prefix(
23324            "// ".to_string(),
23325            "// ".to_string(),
23326            "xx \nyy zz aa bb cc".to_string(),
23327            12,
23328            NonZeroU32::new(4).unwrap(),
23329            false,
23330        ),
23331        "// xx yy zz\n// aa bb cc"
23332    );
23333    assert_eq!(
23334        wrap_with_prefix(
23335            String::new(),
23336            String::new(),
23337            "这是什么 \n 钢笔".to_string(),
23338            3,
23339            NonZeroU32::new(4).unwrap(),
23340            false,
23341        ),
23342        "这是什\n么 钢\n"
23343    );
23344    assert_eq!(
23345        wrap_with_prefix(
23346            String::new(),
23347            String::new(),
23348            format!("foo{}bar", '\u{2009}'), // thin space
23349            80,
23350            NonZeroU32::new(4).unwrap(),
23351            false,
23352        ),
23353        format!("foo{}bar", '\u{2009}')
23354    );
23355}
23356
23357pub trait CollaborationHub {
23358    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23359    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23360    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23361}
23362
23363impl CollaborationHub for Entity<Project> {
23364    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23365        self.read(cx).collaborators()
23366    }
23367
23368    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23369        self.read(cx).user_store().read(cx).participant_indices()
23370    }
23371
23372    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23373        let this = self.read(cx);
23374        let user_ids = this.collaborators().values().map(|c| c.user_id);
23375        this.user_store().read(cx).participant_names(user_ids, cx)
23376    }
23377}
23378
23379pub trait SemanticsProvider {
23380    fn hover(
23381        &self,
23382        buffer: &Entity<Buffer>,
23383        position: text::Anchor,
23384        cx: &mut App,
23385    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23386
23387    fn inline_values(
23388        &self,
23389        buffer_handle: Entity<Buffer>,
23390        range: Range<text::Anchor>,
23391        cx: &mut App,
23392    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23393
23394    fn applicable_inlay_chunks(
23395        &self,
23396        buffer: &Entity<Buffer>,
23397        ranges: &[Range<text::Anchor>],
23398        cx: &mut App,
23399    ) -> Vec<Range<BufferRow>>;
23400
23401    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23402
23403    fn inlay_hints(
23404        &self,
23405        invalidate: InvalidationStrategy,
23406        buffer: Entity<Buffer>,
23407        ranges: Vec<Range<text::Anchor>>,
23408        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23409        cx: &mut App,
23410    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23411
23412    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23413
23414    fn document_highlights(
23415        &self,
23416        buffer: &Entity<Buffer>,
23417        position: text::Anchor,
23418        cx: &mut App,
23419    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23420
23421    fn definitions(
23422        &self,
23423        buffer: &Entity<Buffer>,
23424        position: text::Anchor,
23425        kind: GotoDefinitionKind,
23426        cx: &mut App,
23427    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23428
23429    fn range_for_rename(
23430        &self,
23431        buffer: &Entity<Buffer>,
23432        position: text::Anchor,
23433        cx: &mut App,
23434    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23435
23436    fn perform_rename(
23437        &self,
23438        buffer: &Entity<Buffer>,
23439        position: text::Anchor,
23440        new_name: String,
23441        cx: &mut App,
23442    ) -> Option<Task<Result<ProjectTransaction>>>;
23443}
23444
23445pub trait CompletionProvider {
23446    fn completions(
23447        &self,
23448        excerpt_id: ExcerptId,
23449        buffer: &Entity<Buffer>,
23450        buffer_position: text::Anchor,
23451        trigger: CompletionContext,
23452        window: &mut Window,
23453        cx: &mut Context<Editor>,
23454    ) -> Task<Result<Vec<CompletionResponse>>>;
23455
23456    fn resolve_completions(
23457        &self,
23458        _buffer: Entity<Buffer>,
23459        _completion_indices: Vec<usize>,
23460        _completions: Rc<RefCell<Box<[Completion]>>>,
23461        _cx: &mut Context<Editor>,
23462    ) -> Task<Result<bool>> {
23463        Task::ready(Ok(false))
23464    }
23465
23466    fn apply_additional_edits_for_completion(
23467        &self,
23468        _buffer: Entity<Buffer>,
23469        _completions: Rc<RefCell<Box<[Completion]>>>,
23470        _completion_index: usize,
23471        _push_to_history: bool,
23472        _cx: &mut Context<Editor>,
23473    ) -> Task<Result<Option<language::Transaction>>> {
23474        Task::ready(Ok(None))
23475    }
23476
23477    fn is_completion_trigger(
23478        &self,
23479        buffer: &Entity<Buffer>,
23480        position: language::Anchor,
23481        text: &str,
23482        trigger_in_words: bool,
23483        menu_is_open: bool,
23484        cx: &mut Context<Editor>,
23485    ) -> bool;
23486
23487    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23488
23489    fn sort_completions(&self) -> bool {
23490        true
23491    }
23492
23493    fn filter_completions(&self) -> bool {
23494        true
23495    }
23496
23497    fn show_snippets(&self) -> bool {
23498        false
23499    }
23500}
23501
23502pub trait CodeActionProvider {
23503    fn id(&self) -> Arc<str>;
23504
23505    fn code_actions(
23506        &self,
23507        buffer: &Entity<Buffer>,
23508        range: Range<text::Anchor>,
23509        window: &mut Window,
23510        cx: &mut App,
23511    ) -> Task<Result<Vec<CodeAction>>>;
23512
23513    fn apply_code_action(
23514        &self,
23515        buffer_handle: Entity<Buffer>,
23516        action: CodeAction,
23517        excerpt_id: ExcerptId,
23518        push_to_history: bool,
23519        window: &mut Window,
23520        cx: &mut App,
23521    ) -> Task<Result<ProjectTransaction>>;
23522}
23523
23524impl CodeActionProvider for Entity<Project> {
23525    fn id(&self) -> Arc<str> {
23526        "project".into()
23527    }
23528
23529    fn code_actions(
23530        &self,
23531        buffer: &Entity<Buffer>,
23532        range: Range<text::Anchor>,
23533        _window: &mut Window,
23534        cx: &mut App,
23535    ) -> Task<Result<Vec<CodeAction>>> {
23536        self.update(cx, |project, cx| {
23537            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23538            let code_actions = project.code_actions(buffer, range, None, cx);
23539            cx.background_spawn(async move {
23540                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23541                Ok(code_lens_actions
23542                    .context("code lens fetch")?
23543                    .into_iter()
23544                    .flatten()
23545                    .chain(
23546                        code_actions
23547                            .context("code action fetch")?
23548                            .into_iter()
23549                            .flatten(),
23550                    )
23551                    .collect())
23552            })
23553        })
23554    }
23555
23556    fn apply_code_action(
23557        &self,
23558        buffer_handle: Entity<Buffer>,
23559        action: CodeAction,
23560        _excerpt_id: ExcerptId,
23561        push_to_history: bool,
23562        _window: &mut Window,
23563        cx: &mut App,
23564    ) -> Task<Result<ProjectTransaction>> {
23565        self.update(cx, |project, cx| {
23566            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23567        })
23568    }
23569}
23570
23571fn snippet_completions(
23572    project: &Project,
23573    buffer: &Entity<Buffer>,
23574    buffer_anchor: text::Anchor,
23575    classifier: CharClassifier,
23576    cx: &mut App,
23577) -> Task<Result<CompletionResponse>> {
23578    let languages = buffer.read(cx).languages_at(buffer_anchor);
23579    let snippet_store = project.snippets().read(cx);
23580
23581    let scopes: Vec<_> = languages
23582        .iter()
23583        .filter_map(|language| {
23584            let language_name = language.lsp_id();
23585            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23586
23587            if snippets.is_empty() {
23588                None
23589            } else {
23590                Some((language.default_scope(), snippets))
23591            }
23592        })
23593        .collect();
23594
23595    if scopes.is_empty() {
23596        return Task::ready(Ok(CompletionResponse {
23597            completions: vec![],
23598            display_options: CompletionDisplayOptions::default(),
23599            is_incomplete: false,
23600        }));
23601    }
23602
23603    let snapshot = buffer.read(cx).text_snapshot();
23604    let executor = cx.background_executor().clone();
23605
23606    cx.background_spawn(async move {
23607        let is_word_char = |c| classifier.is_word(c);
23608
23609        let mut is_incomplete = false;
23610        let mut completions: Vec<Completion> = Vec::new();
23611
23612        const MAX_PREFIX_LEN: usize = 128;
23613        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23614        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23615        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23616
23617        let max_buffer_window: String = snapshot
23618            .text_for_range(window_start..buffer_offset)
23619            .collect();
23620
23621        if max_buffer_window.is_empty() {
23622            return Ok(CompletionResponse {
23623                completions: vec![],
23624                display_options: CompletionDisplayOptions::default(),
23625                is_incomplete: true,
23626            });
23627        }
23628
23629        for (_scope, snippets) in scopes.into_iter() {
23630            // Sort snippets by word count to match longer snippet prefixes first.
23631            let mut sorted_snippet_candidates = snippets
23632                .iter()
23633                .enumerate()
23634                .flat_map(|(snippet_ix, snippet)| {
23635                    snippet
23636                        .prefix
23637                        .iter()
23638                        .enumerate()
23639                        .map(move |(prefix_ix, prefix)| {
23640                            let word_count =
23641                                snippet_candidate_suffixes(prefix, is_word_char).count();
23642                            ((snippet_ix, prefix_ix), prefix, word_count)
23643                        })
23644                })
23645                .collect_vec();
23646            sorted_snippet_candidates
23647                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23648
23649            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23650
23651            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23652                .take(
23653                    sorted_snippet_candidates
23654                        .first()
23655                        .map(|(_, _, word_count)| *word_count)
23656                        .unwrap_or_default(),
23657                )
23658                .collect_vec();
23659
23660            const MAX_RESULTS: usize = 100;
23661            // Each match also remembers how many characters from the buffer it consumed
23662            let mut matches: Vec<(StringMatch, usize)> = vec![];
23663
23664            let mut snippet_list_cutoff_index = 0;
23665            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23666                let word_count = buffer_index + 1;
23667                // Increase `snippet_list_cutoff_index` until we have all of the
23668                // snippets with sufficiently many words.
23669                while sorted_snippet_candidates
23670                    .get(snippet_list_cutoff_index)
23671                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23672                        *snippet_word_count >= word_count
23673                    })
23674                {
23675                    snippet_list_cutoff_index += 1;
23676                }
23677
23678                // Take only the candidates with at least `word_count` many words
23679                let snippet_candidates_at_word_len =
23680                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23681
23682                let candidates = snippet_candidates_at_word_len
23683                    .iter()
23684                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23685                    .enumerate() // index in `sorted_snippet_candidates`
23686                    // First char must match
23687                    .filter(|(_ix, prefix)| {
23688                        itertools::equal(
23689                            prefix
23690                                .chars()
23691                                .next()
23692                                .into_iter()
23693                                .flat_map(|c| c.to_lowercase()),
23694                            buffer_window
23695                                .chars()
23696                                .next()
23697                                .into_iter()
23698                                .flat_map(|c| c.to_lowercase()),
23699                        )
23700                    })
23701                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23702                    .collect::<Vec<StringMatchCandidate>>();
23703
23704                matches.extend(
23705                    fuzzy::match_strings(
23706                        &candidates,
23707                        &buffer_window,
23708                        buffer_window.chars().any(|c| c.is_uppercase()),
23709                        true,
23710                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23711                        &Default::default(),
23712                        executor.clone(),
23713                    )
23714                    .await
23715                    .into_iter()
23716                    .map(|string_match| (string_match, buffer_window.len())),
23717                );
23718
23719                if matches.len() >= MAX_RESULTS {
23720                    break;
23721                }
23722            }
23723
23724            let to_lsp = |point: &text::Anchor| {
23725                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23726                point_to_lsp(end)
23727            };
23728            let lsp_end = to_lsp(&buffer_anchor);
23729
23730            if matches.len() >= MAX_RESULTS {
23731                is_incomplete = true;
23732            }
23733
23734            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23735                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23736                    sorted_snippet_candidates[string_match.candidate_id];
23737                let snippet = &snippets[snippet_index];
23738                let start = buffer_offset - buffer_window_len;
23739                let start = snapshot.anchor_before(start);
23740                let range = start..buffer_anchor;
23741                let lsp_start = to_lsp(&start);
23742                let lsp_range = lsp::Range {
23743                    start: lsp_start,
23744                    end: lsp_end,
23745                };
23746                Completion {
23747                    replace_range: range,
23748                    new_text: snippet.body.clone(),
23749                    source: CompletionSource::Lsp {
23750                        insert_range: None,
23751                        server_id: LanguageServerId(usize::MAX),
23752                        resolved: true,
23753                        lsp_completion: Box::new(lsp::CompletionItem {
23754                            label: snippet.prefix.first().unwrap().clone(),
23755                            kind: Some(CompletionItemKind::SNIPPET),
23756                            label_details: snippet.description.as_ref().map(|description| {
23757                                lsp::CompletionItemLabelDetails {
23758                                    detail: Some(description.clone()),
23759                                    description: None,
23760                                }
23761                            }),
23762                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23763                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23764                                lsp::InsertReplaceEdit {
23765                                    new_text: snippet.body.clone(),
23766                                    insert: lsp_range,
23767                                    replace: lsp_range,
23768                                },
23769                            )),
23770                            filter_text: Some(snippet.body.clone()),
23771                            sort_text: Some(char::MAX.to_string()),
23772                            ..lsp::CompletionItem::default()
23773                        }),
23774                        lsp_defaults: None,
23775                    },
23776                    label: CodeLabel {
23777                        text: matching_prefix.clone(),
23778                        runs: Vec::new(),
23779                        filter_range: 0..matching_prefix.len(),
23780                    },
23781                    icon_path: None,
23782                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23783                        single_line: snippet.name.clone().into(),
23784                        plain_text: snippet
23785                            .description
23786                            .clone()
23787                            .map(|description| description.into()),
23788                    }),
23789                    insert_text_mode: None,
23790                    confirm: None,
23791                    match_start: Some(start),
23792                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23793                }
23794            }));
23795        }
23796
23797        Ok(CompletionResponse {
23798            completions,
23799            display_options: CompletionDisplayOptions::default(),
23800            is_incomplete,
23801        })
23802    })
23803}
23804
23805impl CompletionProvider for Entity<Project> {
23806    fn completions(
23807        &self,
23808        _excerpt_id: ExcerptId,
23809        buffer: &Entity<Buffer>,
23810        buffer_position: text::Anchor,
23811        options: CompletionContext,
23812        _window: &mut Window,
23813        cx: &mut Context<Editor>,
23814    ) -> Task<Result<Vec<CompletionResponse>>> {
23815        self.update(cx, |project, cx| {
23816            let task = project.completions(buffer, buffer_position, options, cx);
23817            cx.background_spawn(task)
23818        })
23819    }
23820
23821    fn resolve_completions(
23822        &self,
23823        buffer: Entity<Buffer>,
23824        completion_indices: Vec<usize>,
23825        completions: Rc<RefCell<Box<[Completion]>>>,
23826        cx: &mut Context<Editor>,
23827    ) -> Task<Result<bool>> {
23828        self.update(cx, |project, cx| {
23829            project.lsp_store().update(cx, |lsp_store, cx| {
23830                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23831            })
23832        })
23833    }
23834
23835    fn apply_additional_edits_for_completion(
23836        &self,
23837        buffer: Entity<Buffer>,
23838        completions: Rc<RefCell<Box<[Completion]>>>,
23839        completion_index: usize,
23840        push_to_history: bool,
23841        cx: &mut Context<Editor>,
23842    ) -> Task<Result<Option<language::Transaction>>> {
23843        self.update(cx, |project, cx| {
23844            project.lsp_store().update(cx, |lsp_store, cx| {
23845                lsp_store.apply_additional_edits_for_completion(
23846                    buffer,
23847                    completions,
23848                    completion_index,
23849                    push_to_history,
23850                    cx,
23851                )
23852            })
23853        })
23854    }
23855
23856    fn is_completion_trigger(
23857        &self,
23858        buffer: &Entity<Buffer>,
23859        position: language::Anchor,
23860        text: &str,
23861        trigger_in_words: bool,
23862        menu_is_open: bool,
23863        cx: &mut Context<Editor>,
23864    ) -> bool {
23865        let mut chars = text.chars();
23866        let char = if let Some(char) = chars.next() {
23867            char
23868        } else {
23869            return false;
23870        };
23871        if chars.next().is_some() {
23872            return false;
23873        }
23874
23875        let buffer = buffer.read(cx);
23876        let snapshot = buffer.snapshot();
23877        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23878            return false;
23879        }
23880        let classifier = snapshot
23881            .char_classifier_at(position)
23882            .scope_context(Some(CharScopeContext::Completion));
23883        if trigger_in_words && classifier.is_word(char) {
23884            return true;
23885        }
23886
23887        buffer.completion_triggers().contains(text)
23888    }
23889
23890    fn show_snippets(&self) -> bool {
23891        true
23892    }
23893}
23894
23895impl SemanticsProvider for Entity<Project> {
23896    fn hover(
23897        &self,
23898        buffer: &Entity<Buffer>,
23899        position: text::Anchor,
23900        cx: &mut App,
23901    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23902        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23903    }
23904
23905    fn document_highlights(
23906        &self,
23907        buffer: &Entity<Buffer>,
23908        position: text::Anchor,
23909        cx: &mut App,
23910    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23911        Some(self.update(cx, |project, cx| {
23912            project.document_highlights(buffer, position, cx)
23913        }))
23914    }
23915
23916    fn definitions(
23917        &self,
23918        buffer: &Entity<Buffer>,
23919        position: text::Anchor,
23920        kind: GotoDefinitionKind,
23921        cx: &mut App,
23922    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23923        Some(self.update(cx, |project, cx| match kind {
23924            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23925            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23926            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23927            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23928        }))
23929    }
23930
23931    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23932        self.update(cx, |project, cx| {
23933            if project
23934                .active_debug_session(cx)
23935                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23936            {
23937                return true;
23938            }
23939
23940            buffer.update(cx, |buffer, cx| {
23941                project.any_language_server_supports_inlay_hints(buffer, cx)
23942            })
23943        })
23944    }
23945
23946    fn inline_values(
23947        &self,
23948        buffer_handle: Entity<Buffer>,
23949        range: Range<text::Anchor>,
23950        cx: &mut App,
23951    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23952        self.update(cx, |project, cx| {
23953            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23954
23955            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23956        })
23957    }
23958
23959    fn applicable_inlay_chunks(
23960        &self,
23961        buffer: &Entity<Buffer>,
23962        ranges: &[Range<text::Anchor>],
23963        cx: &mut App,
23964    ) -> Vec<Range<BufferRow>> {
23965        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23966            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23967        })
23968    }
23969
23970    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23971        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23972            lsp_store.invalidate_inlay_hints(for_buffers)
23973        });
23974    }
23975
23976    fn inlay_hints(
23977        &self,
23978        invalidate: InvalidationStrategy,
23979        buffer: Entity<Buffer>,
23980        ranges: Vec<Range<text::Anchor>>,
23981        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23982        cx: &mut App,
23983    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23984        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23985            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23986        }))
23987    }
23988
23989    fn range_for_rename(
23990        &self,
23991        buffer: &Entity<Buffer>,
23992        position: text::Anchor,
23993        cx: &mut App,
23994    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23995        Some(self.update(cx, |project, cx| {
23996            let buffer = buffer.clone();
23997            let task = project.prepare_rename(buffer.clone(), position, cx);
23998            cx.spawn(async move |_, cx| {
23999                Ok(match task.await? {
24000                    PrepareRenameResponse::Success(range) => Some(range),
24001                    PrepareRenameResponse::InvalidPosition => None,
24002                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24003                        // Fallback on using TreeSitter info to determine identifier range
24004                        buffer.read_with(cx, |buffer, _| {
24005                            let snapshot = buffer.snapshot();
24006                            let (range, kind) = snapshot.surrounding_word(position, None);
24007                            if kind != Some(CharKind::Word) {
24008                                return None;
24009                            }
24010                            Some(
24011                                snapshot.anchor_before(range.start)
24012                                    ..snapshot.anchor_after(range.end),
24013                            )
24014                        })?
24015                    }
24016                })
24017            })
24018        }))
24019    }
24020
24021    fn perform_rename(
24022        &self,
24023        buffer: &Entity<Buffer>,
24024        position: text::Anchor,
24025        new_name: String,
24026        cx: &mut App,
24027    ) -> Option<Task<Result<ProjectTransaction>>> {
24028        Some(self.update(cx, |project, cx| {
24029            project.perform_rename(buffer.clone(), position, new_name, cx)
24030        }))
24031    }
24032}
24033
24034fn consume_contiguous_rows(
24035    contiguous_row_selections: &mut Vec<Selection<Point>>,
24036    selection: &Selection<Point>,
24037    display_map: &DisplaySnapshot,
24038    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24039) -> (MultiBufferRow, MultiBufferRow) {
24040    contiguous_row_selections.push(selection.clone());
24041    let start_row = starting_row(selection, display_map);
24042    let mut end_row = ending_row(selection, display_map);
24043
24044    while let Some(next_selection) = selections.peek() {
24045        if next_selection.start.row <= end_row.0 {
24046            end_row = ending_row(next_selection, display_map);
24047            contiguous_row_selections.push(selections.next().unwrap().clone());
24048        } else {
24049            break;
24050        }
24051    }
24052    (start_row, end_row)
24053}
24054
24055fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24056    if selection.start.column > 0 {
24057        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24058    } else {
24059        MultiBufferRow(selection.start.row)
24060    }
24061}
24062
24063fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24064    if next_selection.end.column > 0 || next_selection.is_empty() {
24065        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24066    } else {
24067        MultiBufferRow(next_selection.end.row)
24068    }
24069}
24070
24071impl EditorSnapshot {
24072    pub fn remote_selections_in_range<'a>(
24073        &'a self,
24074        range: &'a Range<Anchor>,
24075        collaboration_hub: &dyn CollaborationHub,
24076        cx: &'a App,
24077    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24078        let participant_names = collaboration_hub.user_names(cx);
24079        let participant_indices = collaboration_hub.user_participant_indices(cx);
24080        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24081        let collaborators_by_replica_id = collaborators_by_peer_id
24082            .values()
24083            .map(|collaborator| (collaborator.replica_id, collaborator))
24084            .collect::<HashMap<_, _>>();
24085        self.buffer_snapshot()
24086            .selections_in_range(range, false)
24087            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24088                if replica_id == ReplicaId::AGENT {
24089                    Some(RemoteSelection {
24090                        replica_id,
24091                        selection,
24092                        cursor_shape,
24093                        line_mode,
24094                        collaborator_id: CollaboratorId::Agent,
24095                        user_name: Some("Agent".into()),
24096                        color: cx.theme().players().agent(),
24097                    })
24098                } else {
24099                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24100                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24101                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24102                    Some(RemoteSelection {
24103                        replica_id,
24104                        selection,
24105                        cursor_shape,
24106                        line_mode,
24107                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24108                        user_name,
24109                        color: if let Some(index) = participant_index {
24110                            cx.theme().players().color_for_participant(index.0)
24111                        } else {
24112                            cx.theme().players().absent()
24113                        },
24114                    })
24115                }
24116            })
24117    }
24118
24119    pub fn hunks_for_ranges(
24120        &self,
24121        ranges: impl IntoIterator<Item = Range<Point>>,
24122    ) -> Vec<MultiBufferDiffHunk> {
24123        let mut hunks = Vec::new();
24124        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24125            HashMap::default();
24126        for query_range in ranges {
24127            let query_rows =
24128                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24129            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24130                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24131            ) {
24132                // Include deleted hunks that are adjacent to the query range, because
24133                // otherwise they would be missed.
24134                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24135                if hunk.status().is_deleted() {
24136                    intersects_range |= hunk.row_range.start == query_rows.end;
24137                    intersects_range |= hunk.row_range.end == query_rows.start;
24138                }
24139                if intersects_range {
24140                    if !processed_buffer_rows
24141                        .entry(hunk.buffer_id)
24142                        .or_default()
24143                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24144                    {
24145                        continue;
24146                    }
24147                    hunks.push(hunk);
24148                }
24149            }
24150        }
24151
24152        hunks
24153    }
24154
24155    fn display_diff_hunks_for_rows<'a>(
24156        &'a self,
24157        display_rows: Range<DisplayRow>,
24158        folded_buffers: &'a HashSet<BufferId>,
24159    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24160        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24161        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24162
24163        self.buffer_snapshot()
24164            .diff_hunks_in_range(buffer_start..buffer_end)
24165            .filter_map(|hunk| {
24166                if folded_buffers.contains(&hunk.buffer_id) {
24167                    return None;
24168                }
24169
24170                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24171                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24172
24173                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24174                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24175
24176                let display_hunk = if hunk_display_start.column() != 0 {
24177                    DisplayDiffHunk::Folded {
24178                        display_row: hunk_display_start.row(),
24179                    }
24180                } else {
24181                    let mut end_row = hunk_display_end.row();
24182                    if hunk_display_end.column() > 0 {
24183                        end_row.0 += 1;
24184                    }
24185                    let is_created_file = hunk.is_created_file();
24186
24187                    DisplayDiffHunk::Unfolded {
24188                        status: hunk.status(),
24189                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24190                            ..hunk.diff_base_byte_range.end.0,
24191                        word_diffs: hunk.word_diffs,
24192                        display_row_range: hunk_display_start.row()..end_row,
24193                        multi_buffer_range: Anchor::range_in_buffer(
24194                            hunk.excerpt_id,
24195                            hunk.buffer_range,
24196                        ),
24197                        is_created_file,
24198                    }
24199                };
24200
24201                Some(display_hunk)
24202            })
24203    }
24204
24205    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24206        self.display_snapshot
24207            .buffer_snapshot()
24208            .language_at(position)
24209    }
24210
24211    pub fn is_focused(&self) -> bool {
24212        self.is_focused
24213    }
24214
24215    pub fn placeholder_text(&self) -> Option<String> {
24216        self.placeholder_display_snapshot
24217            .as_ref()
24218            .map(|display_map| display_map.text())
24219    }
24220
24221    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24222        self.scroll_anchor.scroll_position(&self.display_snapshot)
24223    }
24224
24225    fn gutter_dimensions(
24226        &self,
24227        font_id: FontId,
24228        font_size: Pixels,
24229        max_line_number_width: Pixels,
24230        cx: &App,
24231    ) -> Option<GutterDimensions> {
24232        if !self.show_gutter {
24233            return None;
24234        }
24235
24236        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
24237        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
24238
24239        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24240            matches!(
24241                ProjectSettings::get_global(cx).git.git_gutter,
24242                GitGutterSetting::TrackedFiles
24243            )
24244        });
24245        let gutter_settings = EditorSettings::get_global(cx).gutter;
24246        let show_line_numbers = self
24247            .show_line_numbers
24248            .unwrap_or(gutter_settings.line_numbers);
24249        let line_gutter_width = if show_line_numbers {
24250            // Avoid flicker-like gutter resizes when the line number gains another digit by
24251            // only resizing the gutter on files with > 10**min_line_number_digits lines.
24252            let min_width_for_number_on_gutter =
24253                ch_advance * gutter_settings.min_line_number_digits as f32;
24254            max_line_number_width.max(min_width_for_number_on_gutter)
24255        } else {
24256            0.0.into()
24257        };
24258
24259        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24260        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24261
24262        let git_blame_entries_width =
24263            self.git_blame_gutter_max_author_length
24264                .map(|max_author_length| {
24265                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24266                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24267
24268                    /// The number of characters to dedicate to gaps and margins.
24269                    const SPACING_WIDTH: usize = 4;
24270
24271                    let max_char_count = max_author_length.min(renderer.max_author_length())
24272                        + ::git::SHORT_SHA_LENGTH
24273                        + MAX_RELATIVE_TIMESTAMP.len()
24274                        + SPACING_WIDTH;
24275
24276                    ch_advance * max_char_count
24277                });
24278
24279        let is_singleton = self.buffer_snapshot().is_singleton();
24280
24281        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24282        left_padding += if !is_singleton {
24283            ch_width * 4.0
24284        } else if show_runnables || show_breakpoints {
24285            ch_width * 3.0
24286        } else if show_git_gutter && show_line_numbers {
24287            ch_width * 2.0
24288        } else if show_git_gutter || show_line_numbers {
24289            ch_width
24290        } else {
24291            px(0.)
24292        };
24293
24294        let shows_folds = is_singleton && gutter_settings.folds;
24295
24296        let right_padding = if shows_folds && show_line_numbers {
24297            ch_width * 4.0
24298        } else if shows_folds || (!is_singleton && show_line_numbers) {
24299            ch_width * 3.0
24300        } else if show_line_numbers {
24301            ch_width
24302        } else {
24303            px(0.)
24304        };
24305
24306        Some(GutterDimensions {
24307            left_padding,
24308            right_padding,
24309            width: line_gutter_width + left_padding + right_padding,
24310            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24311            git_blame_entries_width,
24312        })
24313    }
24314
24315    pub fn render_crease_toggle(
24316        &self,
24317        buffer_row: MultiBufferRow,
24318        row_contains_cursor: bool,
24319        editor: Entity<Editor>,
24320        window: &mut Window,
24321        cx: &mut App,
24322    ) -> Option<AnyElement> {
24323        let folded = self.is_line_folded(buffer_row);
24324        let mut is_foldable = false;
24325
24326        if let Some(crease) = self
24327            .crease_snapshot
24328            .query_row(buffer_row, self.buffer_snapshot())
24329        {
24330            is_foldable = true;
24331            match crease {
24332                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24333                    if let Some(render_toggle) = render_toggle {
24334                        let toggle_callback =
24335                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24336                                if folded {
24337                                    editor.update(cx, |editor, cx| {
24338                                        editor.fold_at(buffer_row, window, cx)
24339                                    });
24340                                } else {
24341                                    editor.update(cx, |editor, cx| {
24342                                        editor.unfold_at(buffer_row, window, cx)
24343                                    });
24344                                }
24345                            });
24346                        return Some((render_toggle)(
24347                            buffer_row,
24348                            folded,
24349                            toggle_callback,
24350                            window,
24351                            cx,
24352                        ));
24353                    }
24354                }
24355            }
24356        }
24357
24358        is_foldable |= self.starts_indent(buffer_row);
24359
24360        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24361            Some(
24362                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24363                    .toggle_state(folded)
24364                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24365                        if folded {
24366                            this.unfold_at(buffer_row, window, cx);
24367                        } else {
24368                            this.fold_at(buffer_row, window, cx);
24369                        }
24370                    }))
24371                    .into_any_element(),
24372            )
24373        } else {
24374            None
24375        }
24376    }
24377
24378    pub fn render_crease_trailer(
24379        &self,
24380        buffer_row: MultiBufferRow,
24381        window: &mut Window,
24382        cx: &mut App,
24383    ) -> Option<AnyElement> {
24384        let folded = self.is_line_folded(buffer_row);
24385        if let Crease::Inline { render_trailer, .. } = self
24386            .crease_snapshot
24387            .query_row(buffer_row, self.buffer_snapshot())?
24388        {
24389            let render_trailer = render_trailer.as_ref()?;
24390            Some(render_trailer(buffer_row, folded, window, cx))
24391        } else {
24392            None
24393        }
24394    }
24395}
24396
24397impl Deref for EditorSnapshot {
24398    type Target = DisplaySnapshot;
24399
24400    fn deref(&self) -> &Self::Target {
24401        &self.display_snapshot
24402    }
24403}
24404
24405#[derive(Clone, Debug, PartialEq, Eq)]
24406pub enum EditorEvent {
24407    InputIgnored {
24408        text: Arc<str>,
24409    },
24410    InputHandled {
24411        utf16_range_to_replace: Option<Range<isize>>,
24412        text: Arc<str>,
24413    },
24414    ExcerptsAdded {
24415        buffer: Entity<Buffer>,
24416        predecessor: ExcerptId,
24417        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24418    },
24419    ExcerptsRemoved {
24420        ids: Vec<ExcerptId>,
24421        removed_buffer_ids: Vec<BufferId>,
24422    },
24423    BufferFoldToggled {
24424        ids: Vec<ExcerptId>,
24425        folded: bool,
24426    },
24427    ExcerptsEdited {
24428        ids: Vec<ExcerptId>,
24429    },
24430    ExcerptsExpanded {
24431        ids: Vec<ExcerptId>,
24432    },
24433    BufferEdited,
24434    Edited {
24435        transaction_id: clock::Lamport,
24436    },
24437    Reparsed(BufferId),
24438    Focused,
24439    FocusedIn,
24440    Blurred,
24441    DirtyChanged,
24442    Saved,
24443    TitleChanged,
24444    SelectionsChanged {
24445        local: bool,
24446    },
24447    ScrollPositionChanged {
24448        local: bool,
24449        autoscroll: bool,
24450    },
24451    TransactionUndone {
24452        transaction_id: clock::Lamport,
24453    },
24454    TransactionBegun {
24455        transaction_id: clock::Lamport,
24456    },
24457    CursorShapeChanged,
24458    BreadcrumbsChanged,
24459    PushedToNavHistory {
24460        anchor: Anchor,
24461        is_deactivate: bool,
24462    },
24463}
24464
24465impl EventEmitter<EditorEvent> for Editor {}
24466
24467impl Focusable for Editor {
24468    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24469        self.focus_handle.clone()
24470    }
24471}
24472
24473impl Render for Editor {
24474    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24475        let settings = ThemeSettings::get_global(cx);
24476
24477        let mut text_style = match self.mode {
24478            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24479                color: cx.theme().colors().editor_foreground,
24480                font_family: settings.ui_font.family.clone(),
24481                font_features: settings.ui_font.features.clone(),
24482                font_fallbacks: settings.ui_font.fallbacks.clone(),
24483                font_size: rems(0.875).into(),
24484                font_weight: settings.ui_font.weight,
24485                line_height: relative(settings.buffer_line_height.value()),
24486                ..Default::default()
24487            },
24488            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24489                color: cx.theme().colors().editor_foreground,
24490                font_family: settings.buffer_font.family.clone(),
24491                font_features: settings.buffer_font.features.clone(),
24492                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24493                font_size: settings.buffer_font_size(cx).into(),
24494                font_weight: settings.buffer_font.weight,
24495                line_height: relative(settings.buffer_line_height.value()),
24496                ..Default::default()
24497            },
24498        };
24499        if let Some(text_style_refinement) = &self.text_style_refinement {
24500            text_style.refine(text_style_refinement)
24501        }
24502
24503        let background = match self.mode {
24504            EditorMode::SingleLine => cx.theme().system().transparent,
24505            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24506            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24507            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24508        };
24509
24510        EditorElement::new(
24511            &cx.entity(),
24512            EditorStyle {
24513                background,
24514                border: cx.theme().colors().border,
24515                local_player: cx.theme().players().local(),
24516                text: text_style,
24517                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24518                syntax: cx.theme().syntax().clone(),
24519                status: cx.theme().status().clone(),
24520                inlay_hints_style: make_inlay_hints_style(cx),
24521                edit_prediction_styles: make_suggestion_styles(cx),
24522                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24523                show_underlines: self.diagnostics_enabled(),
24524            },
24525        )
24526    }
24527}
24528
24529impl EntityInputHandler for Editor {
24530    fn text_for_range(
24531        &mut self,
24532        range_utf16: Range<usize>,
24533        adjusted_range: &mut Option<Range<usize>>,
24534        _: &mut Window,
24535        cx: &mut Context<Self>,
24536    ) -> Option<String> {
24537        let snapshot = self.buffer.read(cx).read(cx);
24538        let start = snapshot.clip_offset_utf16(
24539            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
24540            Bias::Left,
24541        );
24542        let end = snapshot.clip_offset_utf16(
24543            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
24544            Bias::Right,
24545        );
24546        if (start.0.0..end.0.0) != range_utf16 {
24547            adjusted_range.replace(start.0.0..end.0.0);
24548        }
24549        Some(snapshot.text_for_range(start..end).collect())
24550    }
24551
24552    fn selected_text_range(
24553        &mut self,
24554        ignore_disabled_input: bool,
24555        _: &mut Window,
24556        cx: &mut Context<Self>,
24557    ) -> Option<UTF16Selection> {
24558        // Prevent the IME menu from appearing when holding down an alphabetic key
24559        // while input is disabled.
24560        if !ignore_disabled_input && !self.input_enabled {
24561            return None;
24562        }
24563
24564        let selection = self
24565            .selections
24566            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24567        let range = selection.range();
24568
24569        Some(UTF16Selection {
24570            range: range.start.0.0..range.end.0.0,
24571            reversed: selection.reversed,
24572        })
24573    }
24574
24575    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24576        let snapshot = self.buffer.read(cx).read(cx);
24577        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24578        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
24579    }
24580
24581    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24582        self.clear_highlights::<InputComposition>(cx);
24583        self.ime_transaction.take();
24584    }
24585
24586    fn replace_text_in_range(
24587        &mut self,
24588        range_utf16: Option<Range<usize>>,
24589        text: &str,
24590        window: &mut Window,
24591        cx: &mut Context<Self>,
24592    ) {
24593        if !self.input_enabled {
24594            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24595            return;
24596        }
24597
24598        self.transact(window, cx, |this, window, cx| {
24599            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24600                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24601                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24602                Some(this.selection_replacement_ranges(range_utf16, cx))
24603            } else {
24604                this.marked_text_ranges(cx)
24605            };
24606
24607            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24608                let newest_selection_id = this.selections.newest_anchor().id;
24609                this.selections
24610                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24611                    .iter()
24612                    .zip(ranges_to_replace.iter())
24613                    .find_map(|(selection, range)| {
24614                        if selection.id == newest_selection_id {
24615                            Some(
24616                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24617                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24618                            )
24619                        } else {
24620                            None
24621                        }
24622                    })
24623            });
24624
24625            cx.emit(EditorEvent::InputHandled {
24626                utf16_range_to_replace: range_to_replace,
24627                text: text.into(),
24628            });
24629
24630            if let Some(new_selected_ranges) = new_selected_ranges {
24631                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24632                    selections.select_ranges(new_selected_ranges)
24633                });
24634                this.backspace(&Default::default(), window, cx);
24635            }
24636
24637            this.handle_input(text, window, cx);
24638        });
24639
24640        if let Some(transaction) = self.ime_transaction {
24641            self.buffer.update(cx, |buffer, cx| {
24642                buffer.group_until_transaction(transaction, cx);
24643            });
24644        }
24645
24646        self.unmark_text(window, cx);
24647    }
24648
24649    fn replace_and_mark_text_in_range(
24650        &mut self,
24651        range_utf16: Option<Range<usize>>,
24652        text: &str,
24653        new_selected_range_utf16: Option<Range<usize>>,
24654        window: &mut Window,
24655        cx: &mut Context<Self>,
24656    ) {
24657        if !self.input_enabled {
24658            return;
24659        }
24660
24661        let transaction = self.transact(window, cx, |this, window, cx| {
24662            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24663                let snapshot = this.buffer.read(cx).read(cx);
24664                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24665                    for marked_range in &mut marked_ranges {
24666                        marked_range.end = marked_range.start + relative_range_utf16.end;
24667                        marked_range.start += relative_range_utf16.start;
24668                        marked_range.start =
24669                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24670                        marked_range.end =
24671                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24672                    }
24673                }
24674                Some(marked_ranges)
24675            } else if let Some(range_utf16) = range_utf16 {
24676                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24677                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24678                Some(this.selection_replacement_ranges(range_utf16, cx))
24679            } else {
24680                None
24681            };
24682
24683            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24684                let newest_selection_id = this.selections.newest_anchor().id;
24685                this.selections
24686                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24687                    .iter()
24688                    .zip(ranges_to_replace.iter())
24689                    .find_map(|(selection, range)| {
24690                        if selection.id == newest_selection_id {
24691                            Some(
24692                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24693                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24694                            )
24695                        } else {
24696                            None
24697                        }
24698                    })
24699            });
24700
24701            cx.emit(EditorEvent::InputHandled {
24702                utf16_range_to_replace: range_to_replace,
24703                text: text.into(),
24704            });
24705
24706            if let Some(ranges) = ranges_to_replace {
24707                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24708                    s.select_ranges(ranges)
24709                });
24710            }
24711
24712            let marked_ranges = {
24713                let snapshot = this.buffer.read(cx).read(cx);
24714                this.selections
24715                    .disjoint_anchors_arc()
24716                    .iter()
24717                    .map(|selection| {
24718                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24719                    })
24720                    .collect::<Vec<_>>()
24721            };
24722
24723            if text.is_empty() {
24724                this.unmark_text(window, cx);
24725            } else {
24726                this.highlight_text::<InputComposition>(
24727                    marked_ranges.clone(),
24728                    HighlightStyle {
24729                        underline: Some(UnderlineStyle {
24730                            thickness: px(1.),
24731                            color: None,
24732                            wavy: false,
24733                        }),
24734                        ..Default::default()
24735                    },
24736                    cx,
24737                );
24738            }
24739
24740            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24741            let use_autoclose = this.use_autoclose;
24742            let use_auto_surround = this.use_auto_surround;
24743            this.set_use_autoclose(false);
24744            this.set_use_auto_surround(false);
24745            this.handle_input(text, window, cx);
24746            this.set_use_autoclose(use_autoclose);
24747            this.set_use_auto_surround(use_auto_surround);
24748
24749            if let Some(new_selected_range) = new_selected_range_utf16 {
24750                let snapshot = this.buffer.read(cx).read(cx);
24751                let new_selected_ranges = marked_ranges
24752                    .into_iter()
24753                    .map(|marked_range| {
24754                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24755                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
24756                            insertion_start.0 + new_selected_range.start,
24757                        ));
24758                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
24759                            insertion_start.0 + new_selected_range.end,
24760                        ));
24761                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24762                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24763                    })
24764                    .collect::<Vec<_>>();
24765
24766                drop(snapshot);
24767                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24768                    selections.select_ranges(new_selected_ranges)
24769                });
24770            }
24771        });
24772
24773        self.ime_transaction = self.ime_transaction.or(transaction);
24774        if let Some(transaction) = self.ime_transaction {
24775            self.buffer.update(cx, |buffer, cx| {
24776                buffer.group_until_transaction(transaction, cx);
24777            });
24778        }
24779
24780        if self.text_highlights::<InputComposition>(cx).is_none() {
24781            self.ime_transaction.take();
24782        }
24783    }
24784
24785    fn bounds_for_range(
24786        &mut self,
24787        range_utf16: Range<usize>,
24788        element_bounds: gpui::Bounds<Pixels>,
24789        window: &mut Window,
24790        cx: &mut Context<Self>,
24791    ) -> Option<gpui::Bounds<Pixels>> {
24792        let text_layout_details = self.text_layout_details(window);
24793        let CharacterDimensions {
24794            em_width,
24795            em_advance,
24796            line_height,
24797        } = self.character_dimensions(window);
24798
24799        let snapshot = self.snapshot(window, cx);
24800        let scroll_position = snapshot.scroll_position();
24801        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24802
24803        let start =
24804            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
24805        let x = Pixels::from(
24806            ScrollOffset::from(
24807                snapshot.x_for_display_point(start, &text_layout_details)
24808                    + self.gutter_dimensions.full_width(),
24809            ) - scroll_left,
24810        );
24811        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24812
24813        Some(Bounds {
24814            origin: element_bounds.origin + point(x, y),
24815            size: size(em_width, line_height),
24816        })
24817    }
24818
24819    fn character_index_for_point(
24820        &mut self,
24821        point: gpui::Point<Pixels>,
24822        _window: &mut Window,
24823        _cx: &mut Context<Self>,
24824    ) -> Option<usize> {
24825        let position_map = self.last_position_map.as_ref()?;
24826        if !position_map.text_hitbox.contains(&point) {
24827            return None;
24828        }
24829        let display_point = position_map.point_for_position(point).previous_valid;
24830        let anchor = position_map
24831            .snapshot
24832            .display_point_to_anchor(display_point, Bias::Left);
24833        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24834        Some(utf16_offset.0.0)
24835    }
24836
24837    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24838        self.input_enabled
24839    }
24840}
24841
24842trait SelectionExt {
24843    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24844    fn spanned_rows(
24845        &self,
24846        include_end_if_at_line_start: bool,
24847        map: &DisplaySnapshot,
24848    ) -> Range<MultiBufferRow>;
24849}
24850
24851impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24852    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24853        let start = self
24854            .start
24855            .to_point(map.buffer_snapshot())
24856            .to_display_point(map);
24857        let end = self
24858            .end
24859            .to_point(map.buffer_snapshot())
24860            .to_display_point(map);
24861        if self.reversed {
24862            end..start
24863        } else {
24864            start..end
24865        }
24866    }
24867
24868    fn spanned_rows(
24869        &self,
24870        include_end_if_at_line_start: bool,
24871        map: &DisplaySnapshot,
24872    ) -> Range<MultiBufferRow> {
24873        let start = self.start.to_point(map.buffer_snapshot());
24874        let mut end = self.end.to_point(map.buffer_snapshot());
24875        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24876            end.row -= 1;
24877        }
24878
24879        let buffer_start = map.prev_line_boundary(start).0;
24880        let buffer_end = map.next_line_boundary(end).0;
24881        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24882    }
24883}
24884
24885impl<T: InvalidationRegion> InvalidationStack<T> {
24886    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24887    where
24888        S: Clone + ToOffset,
24889    {
24890        while let Some(region) = self.last() {
24891            let all_selections_inside_invalidation_ranges =
24892                if selections.len() == region.ranges().len() {
24893                    selections
24894                        .iter()
24895                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24896                        .all(|(selection, invalidation_range)| {
24897                            let head = selection.head().to_offset(buffer);
24898                            invalidation_range.start <= head && invalidation_range.end >= head
24899                        })
24900                } else {
24901                    false
24902                };
24903
24904            if all_selections_inside_invalidation_ranges {
24905                break;
24906            } else {
24907                self.pop();
24908            }
24909        }
24910    }
24911}
24912
24913impl<T> Default for InvalidationStack<T> {
24914    fn default() -> Self {
24915        Self(Default::default())
24916    }
24917}
24918
24919impl<T> Deref for InvalidationStack<T> {
24920    type Target = Vec<T>;
24921
24922    fn deref(&self) -> &Self::Target {
24923        &self.0
24924    }
24925}
24926
24927impl<T> DerefMut for InvalidationStack<T> {
24928    fn deref_mut(&mut self) -> &mut Self::Target {
24929        &mut self.0
24930    }
24931}
24932
24933impl InvalidationRegion for SnippetState {
24934    fn ranges(&self) -> &[Range<Anchor>] {
24935        &self.ranges[self.active_index]
24936    }
24937}
24938
24939fn edit_prediction_edit_text(
24940    current_snapshot: &BufferSnapshot,
24941    edits: &[(Range<Anchor>, impl AsRef<str>)],
24942    edit_preview: &EditPreview,
24943    include_deletions: bool,
24944    cx: &App,
24945) -> HighlightedText {
24946    let edits = edits
24947        .iter()
24948        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24949        .collect::<Vec<_>>();
24950
24951    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24952}
24953
24954fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24955    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24956    // Just show the raw edit text with basic styling
24957    let mut text = String::new();
24958    let mut highlights = Vec::new();
24959
24960    let insertion_highlight_style = HighlightStyle {
24961        color: Some(cx.theme().colors().text),
24962        ..Default::default()
24963    };
24964
24965    for (_, edit_text) in edits {
24966        let start_offset = text.len();
24967        text.push_str(edit_text);
24968        let end_offset = text.len();
24969
24970        if start_offset < end_offset {
24971            highlights.push((start_offset..end_offset, insertion_highlight_style));
24972        }
24973    }
24974
24975    HighlightedText {
24976        text: text.into(),
24977        highlights,
24978    }
24979}
24980
24981pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24982    match severity {
24983        lsp::DiagnosticSeverity::ERROR => colors.error,
24984        lsp::DiagnosticSeverity::WARNING => colors.warning,
24985        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24986        lsp::DiagnosticSeverity::HINT => colors.info,
24987        _ => colors.ignored,
24988    }
24989}
24990
24991pub fn styled_runs_for_code_label<'a>(
24992    label: &'a CodeLabel,
24993    syntax_theme: &'a theme::SyntaxTheme,
24994    local_player: &'a theme::PlayerColor,
24995) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24996    let fade_out = HighlightStyle {
24997        fade_out: Some(0.35),
24998        ..Default::default()
24999    };
25000
25001    let mut prev_end = label.filter_range.end;
25002    label
25003        .runs
25004        .iter()
25005        .enumerate()
25006        .flat_map(move |(ix, (range, highlight_id))| {
25007            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25008                HighlightStyle {
25009                    color: Some(local_player.cursor),
25010                    ..Default::default()
25011                }
25012            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25013                HighlightStyle {
25014                    background_color: Some(local_player.selection),
25015                    ..Default::default()
25016                }
25017            } else if let Some(style) = highlight_id.style(syntax_theme) {
25018                style
25019            } else {
25020                return Default::default();
25021            };
25022            let muted_style = style.highlight(fade_out);
25023
25024            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25025            if range.start >= label.filter_range.end {
25026                if range.start > prev_end {
25027                    runs.push((prev_end..range.start, fade_out));
25028                }
25029                runs.push((range.clone(), muted_style));
25030            } else if range.end <= label.filter_range.end {
25031                runs.push((range.clone(), style));
25032            } else {
25033                runs.push((range.start..label.filter_range.end, style));
25034                runs.push((label.filter_range.end..range.end, muted_style));
25035            }
25036            prev_end = cmp::max(prev_end, range.end);
25037
25038            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25039                runs.push((prev_end..label.text.len(), fade_out));
25040            }
25041
25042            runs
25043        })
25044}
25045
25046pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25047    let mut prev_index = 0;
25048    let mut prev_codepoint: Option<char> = None;
25049    text.char_indices()
25050        .chain([(text.len(), '\0')])
25051        .filter_map(move |(index, codepoint)| {
25052            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25053            let is_boundary = index == text.len()
25054                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25055                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25056            if is_boundary {
25057                let chunk = &text[prev_index..index];
25058                prev_index = index;
25059                Some(chunk)
25060            } else {
25061                None
25062            }
25063        })
25064}
25065
25066/// Given a string of text immediately before the cursor, iterates over possible
25067/// strings a snippet could match to. More precisely: returns an iterator over
25068/// suffixes of `text` created by splitting at word boundaries (before & after
25069/// every non-word character).
25070///
25071/// Shorter suffixes are returned first.
25072pub(crate) fn snippet_candidate_suffixes(
25073    text: &str,
25074    is_word_char: impl Fn(char) -> bool,
25075) -> impl std::iter::Iterator<Item = &str> {
25076    let mut prev_index = text.len();
25077    let mut prev_codepoint = None;
25078    text.char_indices()
25079        .rev()
25080        .chain([(0, '\0')])
25081        .filter_map(move |(index, codepoint)| {
25082            let prev_index = std::mem::replace(&mut prev_index, index);
25083            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25084            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25085                None
25086            } else {
25087                let chunk = &text[prev_index..]; // go to end of string
25088                Some(chunk)
25089            }
25090        })
25091}
25092
25093pub trait RangeToAnchorExt: Sized {
25094    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25095
25096    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25097        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25098        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25099    }
25100}
25101
25102impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25103    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25104        let start_offset = self.start.to_offset(snapshot);
25105        let end_offset = self.end.to_offset(snapshot);
25106        if start_offset == end_offset {
25107            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25108        } else {
25109            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25110        }
25111    }
25112}
25113
25114pub trait RowExt {
25115    fn as_f64(&self) -> f64;
25116
25117    fn next_row(&self) -> Self;
25118
25119    fn previous_row(&self) -> Self;
25120
25121    fn minus(&self, other: Self) -> u32;
25122}
25123
25124impl RowExt for DisplayRow {
25125    fn as_f64(&self) -> f64 {
25126        self.0 as _
25127    }
25128
25129    fn next_row(&self) -> Self {
25130        Self(self.0 + 1)
25131    }
25132
25133    fn previous_row(&self) -> Self {
25134        Self(self.0.saturating_sub(1))
25135    }
25136
25137    fn minus(&self, other: Self) -> u32 {
25138        self.0 - other.0
25139    }
25140}
25141
25142impl RowExt for MultiBufferRow {
25143    fn as_f64(&self) -> f64 {
25144        self.0 as _
25145    }
25146
25147    fn next_row(&self) -> Self {
25148        Self(self.0 + 1)
25149    }
25150
25151    fn previous_row(&self) -> Self {
25152        Self(self.0.saturating_sub(1))
25153    }
25154
25155    fn minus(&self, other: Self) -> u32 {
25156        self.0 - other.0
25157    }
25158}
25159
25160trait RowRangeExt {
25161    type Row;
25162
25163    fn len(&self) -> usize;
25164
25165    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25166}
25167
25168impl RowRangeExt for Range<MultiBufferRow> {
25169    type Row = MultiBufferRow;
25170
25171    fn len(&self) -> usize {
25172        (self.end.0 - self.start.0) as usize
25173    }
25174
25175    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25176        (self.start.0..self.end.0).map(MultiBufferRow)
25177    }
25178}
25179
25180impl RowRangeExt for Range<DisplayRow> {
25181    type Row = DisplayRow;
25182
25183    fn len(&self) -> usize {
25184        (self.end.0 - self.start.0) as usize
25185    }
25186
25187    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25188        (self.start.0..self.end.0).map(DisplayRow)
25189    }
25190}
25191
25192/// If select range has more than one line, we
25193/// just point the cursor to range.start.
25194fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25195    if range.start.row == range.end.row {
25196        range
25197    } else {
25198        range.start..range.start
25199    }
25200}
25201pub struct KillRing(ClipboardItem);
25202impl Global for KillRing {}
25203
25204const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25205
25206enum BreakpointPromptEditAction {
25207    Log,
25208    Condition,
25209    HitCondition,
25210}
25211
25212struct BreakpointPromptEditor {
25213    pub(crate) prompt: Entity<Editor>,
25214    editor: WeakEntity<Editor>,
25215    breakpoint_anchor: Anchor,
25216    breakpoint: Breakpoint,
25217    edit_action: BreakpointPromptEditAction,
25218    block_ids: HashSet<CustomBlockId>,
25219    editor_margins: Arc<Mutex<EditorMargins>>,
25220    _subscriptions: Vec<Subscription>,
25221}
25222
25223impl BreakpointPromptEditor {
25224    const MAX_LINES: u8 = 4;
25225
25226    fn new(
25227        editor: WeakEntity<Editor>,
25228        breakpoint_anchor: Anchor,
25229        breakpoint: Breakpoint,
25230        edit_action: BreakpointPromptEditAction,
25231        window: &mut Window,
25232        cx: &mut Context<Self>,
25233    ) -> Self {
25234        let base_text = match edit_action {
25235            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25236            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25237            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25238        }
25239        .map(|msg| msg.to_string())
25240        .unwrap_or_default();
25241
25242        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25243        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25244
25245        let prompt = cx.new(|cx| {
25246            let mut prompt = Editor::new(
25247                EditorMode::AutoHeight {
25248                    min_lines: 1,
25249                    max_lines: Some(Self::MAX_LINES as usize),
25250                },
25251                buffer,
25252                None,
25253                window,
25254                cx,
25255            );
25256            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25257            prompt.set_show_cursor_when_unfocused(false, cx);
25258            prompt.set_placeholder_text(
25259                match edit_action {
25260                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25261                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25262                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25263                },
25264                window,
25265                cx,
25266            );
25267
25268            prompt
25269        });
25270
25271        Self {
25272            prompt,
25273            editor,
25274            breakpoint_anchor,
25275            breakpoint,
25276            edit_action,
25277            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25278            block_ids: Default::default(),
25279            _subscriptions: vec![],
25280        }
25281    }
25282
25283    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25284        self.block_ids.extend(block_ids)
25285    }
25286
25287    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25288        if let Some(editor) = self.editor.upgrade() {
25289            let message = self
25290                .prompt
25291                .read(cx)
25292                .buffer
25293                .read(cx)
25294                .as_singleton()
25295                .expect("A multi buffer in breakpoint prompt isn't possible")
25296                .read(cx)
25297                .as_rope()
25298                .to_string();
25299
25300            editor.update(cx, |editor, cx| {
25301                editor.edit_breakpoint_at_anchor(
25302                    self.breakpoint_anchor,
25303                    self.breakpoint.clone(),
25304                    match self.edit_action {
25305                        BreakpointPromptEditAction::Log => {
25306                            BreakpointEditAction::EditLogMessage(message.into())
25307                        }
25308                        BreakpointPromptEditAction::Condition => {
25309                            BreakpointEditAction::EditCondition(message.into())
25310                        }
25311                        BreakpointPromptEditAction::HitCondition => {
25312                            BreakpointEditAction::EditHitCondition(message.into())
25313                        }
25314                    },
25315                    cx,
25316                );
25317
25318                editor.remove_blocks(self.block_ids.clone(), None, cx);
25319                cx.focus_self(window);
25320            });
25321        }
25322    }
25323
25324    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25325        self.editor
25326            .update(cx, |editor, cx| {
25327                editor.remove_blocks(self.block_ids.clone(), None, cx);
25328                window.focus(&editor.focus_handle);
25329            })
25330            .log_err();
25331    }
25332
25333    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25334        let settings = ThemeSettings::get_global(cx);
25335        let text_style = TextStyle {
25336            color: if self.prompt.read(cx).read_only(cx) {
25337                cx.theme().colors().text_disabled
25338            } else {
25339                cx.theme().colors().text
25340            },
25341            font_family: settings.buffer_font.family.clone(),
25342            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25343            font_size: settings.buffer_font_size(cx).into(),
25344            font_weight: settings.buffer_font.weight,
25345            line_height: relative(settings.buffer_line_height.value()),
25346            ..Default::default()
25347        };
25348        EditorElement::new(
25349            &self.prompt,
25350            EditorStyle {
25351                background: cx.theme().colors().editor_background,
25352                local_player: cx.theme().players().local(),
25353                text: text_style,
25354                ..Default::default()
25355            },
25356        )
25357    }
25358}
25359
25360impl Render for BreakpointPromptEditor {
25361    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25362        let editor_margins = *self.editor_margins.lock();
25363        let gutter_dimensions = editor_margins.gutter;
25364        h_flex()
25365            .key_context("Editor")
25366            .bg(cx.theme().colors().editor_background)
25367            .border_y_1()
25368            .border_color(cx.theme().status().info_border)
25369            .size_full()
25370            .py(window.line_height() / 2.5)
25371            .on_action(cx.listener(Self::confirm))
25372            .on_action(cx.listener(Self::cancel))
25373            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25374            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25375    }
25376}
25377
25378impl Focusable for BreakpointPromptEditor {
25379    fn focus_handle(&self, cx: &App) -> FocusHandle {
25380        self.prompt.focus_handle(cx)
25381    }
25382}
25383
25384fn all_edits_insertions_or_deletions(
25385    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25386    snapshot: &MultiBufferSnapshot,
25387) -> bool {
25388    let mut all_insertions = true;
25389    let mut all_deletions = true;
25390
25391    for (range, new_text) in edits.iter() {
25392        let range_is_empty = range.to_offset(snapshot).is_empty();
25393        let text_is_empty = new_text.is_empty();
25394
25395        if range_is_empty != text_is_empty {
25396            if range_is_empty {
25397                all_deletions = false;
25398            } else {
25399                all_insertions = false;
25400            }
25401        } else {
25402            return false;
25403        }
25404
25405        if !all_insertions && !all_deletions {
25406            return false;
25407        }
25408    }
25409    all_insertions || all_deletions
25410}
25411
25412struct MissingEditPredictionKeybindingTooltip;
25413
25414impl Render for MissingEditPredictionKeybindingTooltip {
25415    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25416        ui::tooltip_container(cx, |container, cx| {
25417            container
25418                .flex_shrink_0()
25419                .max_w_80()
25420                .min_h(rems_from_px(124.))
25421                .justify_between()
25422                .child(
25423                    v_flex()
25424                        .flex_1()
25425                        .text_ui_sm(cx)
25426                        .child(Label::new("Conflict with Accept Keybinding"))
25427                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25428                )
25429                .child(
25430                    h_flex()
25431                        .pb_1()
25432                        .gap_1()
25433                        .items_end()
25434                        .w_full()
25435                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25436                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25437                        }))
25438                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25439                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25440                        })),
25441                )
25442        })
25443    }
25444}
25445
25446#[derive(Debug, Clone, Copy, PartialEq)]
25447pub struct LineHighlight {
25448    pub background: Background,
25449    pub border: Option<gpui::Hsla>,
25450    pub include_gutter: bool,
25451    pub type_id: Option<TypeId>,
25452}
25453
25454struct LineManipulationResult {
25455    pub new_text: String,
25456    pub line_count_before: usize,
25457    pub line_count_after: usize,
25458}
25459
25460fn render_diff_hunk_controls(
25461    row: u32,
25462    status: &DiffHunkStatus,
25463    hunk_range: Range<Anchor>,
25464    is_created_file: bool,
25465    line_height: Pixels,
25466    editor: &Entity<Editor>,
25467    _window: &mut Window,
25468    cx: &mut App,
25469) -> AnyElement {
25470    h_flex()
25471        .h(line_height)
25472        .mr_1()
25473        .gap_1()
25474        .px_0p5()
25475        .pb_1()
25476        .border_x_1()
25477        .border_b_1()
25478        .border_color(cx.theme().colors().border_variant)
25479        .rounded_b_lg()
25480        .bg(cx.theme().colors().editor_background)
25481        .gap_1()
25482        .block_mouse_except_scroll()
25483        .shadow_md()
25484        .child(if status.has_secondary_hunk() {
25485            Button::new(("stage", row as u64), "Stage")
25486                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25487                .tooltip({
25488                    let focus_handle = editor.focus_handle(cx);
25489                    move |_window, cx| {
25490                        Tooltip::for_action_in(
25491                            "Stage Hunk",
25492                            &::git::ToggleStaged,
25493                            &focus_handle,
25494                            cx,
25495                        )
25496                    }
25497                })
25498                .on_click({
25499                    let editor = editor.clone();
25500                    move |_event, _window, cx| {
25501                        editor.update(cx, |editor, cx| {
25502                            editor.stage_or_unstage_diff_hunks(
25503                                true,
25504                                vec![hunk_range.start..hunk_range.start],
25505                                cx,
25506                            );
25507                        });
25508                    }
25509                })
25510        } else {
25511            Button::new(("unstage", row as u64), "Unstage")
25512                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25513                .tooltip({
25514                    let focus_handle = editor.focus_handle(cx);
25515                    move |_window, cx| {
25516                        Tooltip::for_action_in(
25517                            "Unstage Hunk",
25518                            &::git::ToggleStaged,
25519                            &focus_handle,
25520                            cx,
25521                        )
25522                    }
25523                })
25524                .on_click({
25525                    let editor = editor.clone();
25526                    move |_event, _window, cx| {
25527                        editor.update(cx, |editor, cx| {
25528                            editor.stage_or_unstage_diff_hunks(
25529                                false,
25530                                vec![hunk_range.start..hunk_range.start],
25531                                cx,
25532                            );
25533                        });
25534                    }
25535                })
25536        })
25537        .child(
25538            Button::new(("restore", row as u64), "Restore")
25539                .tooltip({
25540                    let focus_handle = editor.focus_handle(cx);
25541                    move |_window, cx| {
25542                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25543                    }
25544                })
25545                .on_click({
25546                    let editor = editor.clone();
25547                    move |_event, window, cx| {
25548                        editor.update(cx, |editor, cx| {
25549                            let snapshot = editor.snapshot(window, cx);
25550                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25551                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25552                        });
25553                    }
25554                })
25555                .disabled(is_created_file),
25556        )
25557        .when(
25558            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25559            |el| {
25560                el.child(
25561                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25562                        .shape(IconButtonShape::Square)
25563                        .icon_size(IconSize::Small)
25564                        // .disabled(!has_multiple_hunks)
25565                        .tooltip({
25566                            let focus_handle = editor.focus_handle(cx);
25567                            move |_window, cx| {
25568                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25569                            }
25570                        })
25571                        .on_click({
25572                            let editor = editor.clone();
25573                            move |_event, window, cx| {
25574                                editor.update(cx, |editor, cx| {
25575                                    let snapshot = editor.snapshot(window, cx);
25576                                    let position =
25577                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25578                                    editor.go_to_hunk_before_or_after_position(
25579                                        &snapshot,
25580                                        position,
25581                                        Direction::Next,
25582                                        window,
25583                                        cx,
25584                                    );
25585                                    editor.expand_selected_diff_hunks(cx);
25586                                });
25587                            }
25588                        }),
25589                )
25590                .child(
25591                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25592                        .shape(IconButtonShape::Square)
25593                        .icon_size(IconSize::Small)
25594                        // .disabled(!has_multiple_hunks)
25595                        .tooltip({
25596                            let focus_handle = editor.focus_handle(cx);
25597                            move |_window, cx| {
25598                                Tooltip::for_action_in(
25599                                    "Previous Hunk",
25600                                    &GoToPreviousHunk,
25601                                    &focus_handle,
25602                                    cx,
25603                                )
25604                            }
25605                        })
25606                        .on_click({
25607                            let editor = editor.clone();
25608                            move |_event, window, cx| {
25609                                editor.update(cx, |editor, cx| {
25610                                    let snapshot = editor.snapshot(window, cx);
25611                                    let point =
25612                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25613                                    editor.go_to_hunk_before_or_after_position(
25614                                        &snapshot,
25615                                        point,
25616                                        Direction::Prev,
25617                                        window,
25618                                        cx,
25619                                    );
25620                                    editor.expand_selected_diff_hunks(cx);
25621                                });
25622                            }
25623                        }),
25624                )
25625            },
25626        )
25627        .into_any_element()
25628}
25629
25630pub fn multibuffer_context_lines(cx: &App) -> u32 {
25631    EditorSettings::try_get(cx)
25632        .map(|settings| settings.excerpt_context_lines)
25633        .unwrap_or(2)
25634        .min(32)
25635}