editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15pub mod blink_manager;
   16mod bracket_colorization;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlays;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39mod split;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction_types::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use inlays::Inlay;
   65pub use items::MAX_TAB_TITLE_LEN;
   66pub use lsp::CompletionContext;
   67pub use lsp_ext::lsp_tasks;
   68pub use multi_buffer::{
   69    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   70    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   71    ToPoint,
   72};
   73pub use split::SplittableEditor;
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79    status::FileStatus,
   80};
   81use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   82use anyhow::{Context as _, Result, anyhow, bail};
   83use blink_manager::BlinkManager;
   84use buffer_diff::DiffHunkStatus;
   85use client::{Collaborator, ParticipantIndex, parse_zed_link};
   86use clock::ReplicaId;
   87use code_context_menus::{
   88    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   89    CompletionsMenu, ContextMenuOrigin,
   90};
   91use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   92use convert_case::{Case, Casing};
   93use dap::TelemetrySpawnLocation;
   94use display_map::*;
   95use edit_prediction_types::{EditPredictionDelegate, EditPredictionDelegateHandle};
   96use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   97use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   98use futures::{
   99    FutureExt, StreamExt as _,
  100    future::{self, Shared, join},
  101    stream::FuturesUnordered,
  102};
  103use fuzzy::{StringMatch, StringMatchCandidate};
  104use git::blame::{GitBlame, GlobalBlameRenderer};
  105use gpui::{
  106    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  107    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  108    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  109    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  110    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, Render,
  111    ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextRun, TextStyle,
  112    TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity,
  113    WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative, size,
  114};
  115use hover_links::{HoverLink, HoveredLinkState, find_file};
  116use hover_popover::{HoverState, hide_hover};
  117use indent_guides::ActiveIndentGuidesState;
  118use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  119use itertools::{Either, Itertools};
  120use language::{
  121    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  122    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  123    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  124    IndentSize, Language, LanguageName, LanguageRegistry, OffsetRangeExt, OutlineItem, Point,
  125    Runnable, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  126    language_settings::{
  127        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  128        all_language_settings, language_settings,
  129    },
  130    point_from_lsp, point_to_lsp, text_diff_with_options,
  131};
  132use linked_editing_ranges::refresh_linked_ranges;
  133use lsp::{
  134    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  135    LanguageServerId,
  136};
  137use lsp_colors::LspColorData;
  138use markdown::Markdown;
  139use mouse_context_menu::MouseContextMenu;
  140use movement::TextLayoutDetails;
  141use multi_buffer::{
  142    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  143};
  144use parking_lot::Mutex;
  145use persistence::DB;
  146use project::{
  147    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  148    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  149    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  150    ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  151    debugger::{
  152        breakpoint_store::{
  153            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  154            BreakpointStore, BreakpointStoreEvent,
  155        },
  156        session::{Session, SessionEvent},
  157    },
  158    git_store::GitStoreEvent,
  159    lsp_store::{
  160        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  161        OpenLspBufferHandle,
  162    },
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  164};
  165use rand::seq::SliceRandom;
  166use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  167use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  168use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  169use serde::{Deserialize, Serialize};
  170use settings::{
  171    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  172    update_settings_file,
  173};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::{Any, TypeId},
  178    borrow::Cow,
  179    cell::{OnceCell, RefCell},
  180    cmp::{self, Ordering, Reverse},
  181    collections::hash_map,
  182    iter::{self, Peekable},
  183    mem,
  184    num::NonZeroU32,
  185    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  186    path::{Path, PathBuf},
  187    rc::Rc,
  188    sync::Arc,
  189    time::{Duration, Instant},
  190};
  191use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  192use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  193use theme::{
  194    AccentColors, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  195    observe_buffer_font_size_adjustment,
  196};
  197use ui::{
  198    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  199    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  200};
  201use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  202use workspace::{
  203    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  204    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  205    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  206    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  207    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  208    searchable::SearchEvent,
  209};
  210
  211use crate::{
  212    code_context_menus::CompletionsMenuSource,
  213    editor_settings::MultiCursorModifier,
  214    hover_links::{find_url, find_url_from_range},
  215    inlays::{
  216        InlineValueCache,
  217        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  218    },
  219    scroll::{ScrollOffset, ScrollPixelOffset},
  220    selections_collection::resolve_selections_wrapping_blocks,
  221    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  222};
  223
  224pub const FILE_HEADER_HEIGHT: u32 = 2;
  225pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  226const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  227const MAX_LINE_LEN: usize = 1024;
  228const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  229const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  230pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  231#[doc(hidden)]
  232pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  233pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  234
  235pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  236pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  237pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  238pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  239
  240pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  241pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  242pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  243
  244pub type RenderDiffHunkControlsFn = Arc<
  245    dyn Fn(
  246        u32,
  247        &DiffHunkStatus,
  248        Range<Anchor>,
  249        bool,
  250        Pixels,
  251        &Entity<Editor>,
  252        &mut Window,
  253        &mut App,
  254    ) -> AnyElement,
  255>;
  256
  257enum ReportEditorEvent {
  258    Saved { auto_saved: bool },
  259    EditorOpened,
  260    Closed,
  261}
  262
  263impl ReportEditorEvent {
  264    pub fn event_type(&self) -> &'static str {
  265        match self {
  266            Self::Saved { .. } => "Editor Saved",
  267            Self::EditorOpened => "Editor Opened",
  268            Self::Closed => "Editor Closed",
  269        }
  270    }
  271}
  272
  273pub enum ActiveDebugLine {}
  274pub enum DebugStackFrameLine {}
  275enum DocumentHighlightRead {}
  276enum DocumentHighlightWrite {}
  277enum InputComposition {}
  278pub enum PendingInput {}
  279enum SelectedTextHighlight {}
  280
  281pub enum ConflictsOuter {}
  282pub enum ConflictsOurs {}
  283pub enum ConflictsTheirs {}
  284pub enum ConflictsOursMarker {}
  285pub enum ConflictsTheirsMarker {}
  286
  287pub struct HunkAddedColor;
  288pub struct HunkRemovedColor;
  289
  290#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  291pub enum Navigated {
  292    Yes,
  293    No,
  294}
  295
  296impl Navigated {
  297    pub fn from_bool(yes: bool) -> Navigated {
  298        if yes { Navigated::Yes } else { Navigated::No }
  299    }
  300}
  301
  302#[derive(Debug, Clone, PartialEq, Eq)]
  303enum DisplayDiffHunk {
  304    Folded {
  305        display_row: DisplayRow,
  306    },
  307    Unfolded {
  308        is_created_file: bool,
  309        diff_base_byte_range: Range<usize>,
  310        display_row_range: Range<DisplayRow>,
  311        multi_buffer_range: Range<Anchor>,
  312        status: DiffHunkStatus,
  313        word_diffs: Vec<Range<MultiBufferOffset>>,
  314    },
  315}
  316
  317pub enum HideMouseCursorOrigin {
  318    TypingAction,
  319    MovementAction,
  320}
  321
  322pub fn init(cx: &mut App) {
  323    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  324
  325    workspace::register_project_item::<Editor>(cx);
  326    workspace::FollowableViewRegistry::register::<Editor>(cx);
  327    workspace::register_serializable_item::<Editor>(cx);
  328
  329    cx.observe_new(
  330        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  331            workspace.register_action(Editor::new_file);
  332            workspace.register_action(Editor::new_file_split);
  333            workspace.register_action(Editor::new_file_vertical);
  334            workspace.register_action(Editor::new_file_horizontal);
  335            workspace.register_action(Editor::cancel_language_server_work);
  336            workspace.register_action(Editor::toggle_focus);
  337        },
  338    )
  339    .detach();
  340
  341    cx.on_action(move |_: &workspace::NewFile, cx| {
  342        let app_state = workspace::AppState::global(cx);
  343        if let Some(app_state) = app_state.upgrade() {
  344            workspace::open_new(
  345                Default::default(),
  346                app_state,
  347                cx,
  348                |workspace, window, cx| {
  349                    Editor::new_file(workspace, &Default::default(), window, cx)
  350                },
  351            )
  352            .detach();
  353        }
  354    });
  355    cx.on_action(move |_: &workspace::NewWindow, cx| {
  356        let app_state = workspace::AppState::global(cx);
  357        if let Some(app_state) = app_state.upgrade() {
  358            workspace::open_new(
  359                Default::default(),
  360                app_state,
  361                cx,
  362                |workspace, window, cx| {
  363                    cx.activate(true);
  364                    Editor::new_file(workspace, &Default::default(), window, cx)
  365                },
  366            )
  367            .detach();
  368        }
  369    });
  370}
  371
  372pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  373    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  374}
  375
  376pub trait DiagnosticRenderer {
  377    fn render_group(
  378        &self,
  379        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  380        buffer_id: BufferId,
  381        snapshot: EditorSnapshot,
  382        editor: WeakEntity<Editor>,
  383        language_registry: Option<Arc<LanguageRegistry>>,
  384        cx: &mut App,
  385    ) -> Vec<BlockProperties<Anchor>>;
  386
  387    fn render_hover(
  388        &self,
  389        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  390        range: Range<Point>,
  391        buffer_id: BufferId,
  392        language_registry: Option<Arc<LanguageRegistry>>,
  393        cx: &mut App,
  394    ) -> Option<Entity<markdown::Markdown>>;
  395
  396    fn open_link(
  397        &self,
  398        editor: &mut Editor,
  399        link: SharedString,
  400        window: &mut Window,
  401        cx: &mut Context<Editor>,
  402    );
  403}
  404
  405pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  406
  407impl GlobalDiagnosticRenderer {
  408    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  409        cx.try_global::<Self>().map(|g| g.0.clone())
  410    }
  411}
  412
  413impl gpui::Global for GlobalDiagnosticRenderer {}
  414pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  415    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  416}
  417
  418pub struct SearchWithinRange;
  419
  420trait InvalidationRegion {
  421    fn ranges(&self) -> &[Range<Anchor>];
  422}
  423
  424#[derive(Clone, Debug, PartialEq)]
  425pub enum SelectPhase {
  426    Begin {
  427        position: DisplayPoint,
  428        add: bool,
  429        click_count: usize,
  430    },
  431    BeginColumnar {
  432        position: DisplayPoint,
  433        reset: bool,
  434        mode: ColumnarMode,
  435        goal_column: u32,
  436    },
  437    Extend {
  438        position: DisplayPoint,
  439        click_count: usize,
  440    },
  441    Update {
  442        position: DisplayPoint,
  443        goal_column: u32,
  444        scroll_delta: gpui::Point<f32>,
  445    },
  446    End,
  447}
  448
  449#[derive(Clone, Debug, PartialEq)]
  450pub enum ColumnarMode {
  451    FromMouse,
  452    FromSelection,
  453}
  454
  455#[derive(Clone, Debug)]
  456pub enum SelectMode {
  457    Character,
  458    Word(Range<Anchor>),
  459    Line(Range<Anchor>),
  460    All,
  461}
  462
  463#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  464pub enum SizingBehavior {
  465    /// The editor will layout itself using `size_full` and will include the vertical
  466    /// scroll margin as requested by user settings.
  467    #[default]
  468    Default,
  469    /// The editor will layout itself using `size_full`, but will not have any
  470    /// vertical overscroll.
  471    ExcludeOverscrollMargin,
  472    /// The editor will request a vertical size according to its content and will be
  473    /// layouted without a vertical scroll margin.
  474    SizeByContent,
  475}
  476
  477#[derive(Clone, PartialEq, Eq, Debug)]
  478pub enum EditorMode {
  479    SingleLine,
  480    AutoHeight {
  481        min_lines: usize,
  482        max_lines: Option<usize>,
  483    },
  484    Full {
  485        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  486        scale_ui_elements_with_buffer_font_size: bool,
  487        /// When set to `true`, the editor will render a background for the active line.
  488        show_active_line_background: bool,
  489        /// Determines the sizing behavior for this editor
  490        sizing_behavior: SizingBehavior,
  491    },
  492    Minimap {
  493        parent: WeakEntity<Editor>,
  494    },
  495}
  496
  497impl EditorMode {
  498    pub fn full() -> Self {
  499        Self::Full {
  500            scale_ui_elements_with_buffer_font_size: true,
  501            show_active_line_background: true,
  502            sizing_behavior: SizingBehavior::Default,
  503        }
  504    }
  505
  506    #[inline]
  507    pub fn is_full(&self) -> bool {
  508        matches!(self, Self::Full { .. })
  509    }
  510
  511    #[inline]
  512    pub fn is_single_line(&self) -> bool {
  513        matches!(self, Self::SingleLine { .. })
  514    }
  515
  516    #[inline]
  517    fn is_minimap(&self) -> bool {
  518        matches!(self, Self::Minimap { .. })
  519    }
  520}
  521
  522#[derive(Copy, Clone, Debug)]
  523pub enum SoftWrap {
  524    /// Prefer not to wrap at all.
  525    ///
  526    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  527    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  528    GitDiff,
  529    /// Prefer a single line generally, unless an overly long line is encountered.
  530    None,
  531    /// Soft wrap lines that exceed the editor width.
  532    EditorWidth,
  533    /// Soft wrap lines at the preferred line length.
  534    Column(u32),
  535    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  536    Bounded(u32),
  537}
  538
  539#[derive(Clone)]
  540pub struct EditorStyle {
  541    pub background: Hsla,
  542    pub border: Hsla,
  543    pub local_player: PlayerColor,
  544    pub text: TextStyle,
  545    pub scrollbar_width: Pixels,
  546    pub syntax: Arc<SyntaxTheme>,
  547    pub status: StatusColors,
  548    pub inlay_hints_style: HighlightStyle,
  549    pub edit_prediction_styles: EditPredictionStyles,
  550    pub unnecessary_code_fade: f32,
  551    pub show_underlines: bool,
  552}
  553
  554impl Default for EditorStyle {
  555    fn default() -> Self {
  556        Self {
  557            background: Hsla::default(),
  558            border: Hsla::default(),
  559            local_player: PlayerColor::default(),
  560            text: TextStyle::default(),
  561            scrollbar_width: Pixels::default(),
  562            syntax: Default::default(),
  563            // HACK: Status colors don't have a real default.
  564            // We should look into removing the status colors from the editor
  565            // style and retrieve them directly from the theme.
  566            status: StatusColors::dark(),
  567            inlay_hints_style: HighlightStyle::default(),
  568            edit_prediction_styles: EditPredictionStyles {
  569                insertion: HighlightStyle::default(),
  570                whitespace: HighlightStyle::default(),
  571            },
  572            unnecessary_code_fade: Default::default(),
  573            show_underlines: true,
  574        }
  575    }
  576}
  577
  578pub fn make_inlay_hints_style(cx: &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: &App) -> EditPredictionStyles {
  602    EditPredictionStyles {
  603        insertion: HighlightStyle {
  604            color: Some(cx.theme().status().predictive),
  605            ..HighlightStyle::default()
  606        },
  607        whitespace: HighlightStyle {
  608            background_color: Some(cx.theme().status().created_background),
  609            ..HighlightStyle::default()
  610        },
  611    }
  612}
  613
  614type CompletionId = usize;
  615
  616pub(crate) enum EditDisplayMode {
  617    TabAccept,
  618    DiffPopover,
  619    Inline,
  620}
  621
  622enum EditPrediction {
  623    Edit {
  624        edits: Vec<(Range<Anchor>, Arc<str>)>,
  625        edit_preview: Option<EditPreview>,
  626        display_mode: EditDisplayMode,
  627        snapshot: BufferSnapshot,
  628    },
  629    /// Move to a specific location in the active editor
  630    MoveWithin {
  631        target: Anchor,
  632        snapshot: BufferSnapshot,
  633    },
  634    /// Move to a specific location in a different editor (not the active one)
  635    MoveOutside {
  636        target: language::Anchor,
  637        snapshot: BufferSnapshot,
  638    },
  639}
  640
  641struct EditPredictionState {
  642    inlay_ids: Vec<InlayId>,
  643    completion: EditPrediction,
  644    completion_id: Option<SharedString>,
  645    invalidation_range: Option<Range<Anchor>>,
  646}
  647
  648enum EditPredictionSettings {
  649    Disabled,
  650    Enabled {
  651        show_in_menu: bool,
  652        preview_requires_modifier: bool,
  653    },
  654}
  655
  656enum EditPredictionHighlight {}
  657
  658#[derive(Debug, Clone)]
  659struct InlineDiagnostic {
  660    message: SharedString,
  661    group_id: usize,
  662    is_primary: bool,
  663    start: Point,
  664    severity: lsp::DiagnosticSeverity,
  665}
  666
  667pub enum MenuEditPredictionsPolicy {
  668    Never,
  669    ByProvider,
  670}
  671
  672pub enum EditPredictionPreview {
  673    /// Modifier is not pressed
  674    Inactive { released_too_fast: bool },
  675    /// Modifier pressed
  676    Active {
  677        since: Instant,
  678        previous_scroll_position: Option<ScrollAnchor>,
  679    },
  680}
  681
  682impl EditPredictionPreview {
  683    pub fn released_too_fast(&self) -> bool {
  684        match self {
  685            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  686            EditPredictionPreview::Active { .. } => false,
  687        }
  688    }
  689
  690    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  691        if let EditPredictionPreview::Active {
  692            previous_scroll_position,
  693            ..
  694        } = self
  695        {
  696            *previous_scroll_position = scroll_position;
  697        }
  698    }
  699}
  700
  701pub struct ContextMenuOptions {
  702    pub min_entries_visible: usize,
  703    pub max_entries_visible: usize,
  704    pub placement: Option<ContextMenuPlacement>,
  705}
  706
  707#[derive(Debug, Clone, PartialEq, Eq)]
  708pub enum ContextMenuPlacement {
  709    Above,
  710    Below,
  711}
  712
  713#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  714struct EditorActionId(usize);
  715
  716impl EditorActionId {
  717    pub fn post_inc(&mut self) -> Self {
  718        let answer = self.0;
  719
  720        *self = Self(answer + 1);
  721
  722        Self(answer)
  723    }
  724}
  725
  726// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  727// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  728
  729type BackgroundHighlight = (
  730    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  731    Arc<[Range<Anchor>]>,
  732);
  733type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  734
  735#[derive(Default)]
  736struct ScrollbarMarkerState {
  737    scrollbar_size: Size<Pixels>,
  738    dirty: bool,
  739    markers: Arc<[PaintQuad]>,
  740    pending_refresh: Option<Task<Result<()>>>,
  741}
  742
  743impl ScrollbarMarkerState {
  744    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  745        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  746    }
  747}
  748
  749#[derive(Clone, Copy, PartialEq, Eq)]
  750pub enum MinimapVisibility {
  751    Disabled,
  752    Enabled {
  753        /// The configuration currently present in the users settings.
  754        setting_configuration: bool,
  755        /// Whether to override the currently set visibility from the users setting.
  756        toggle_override: bool,
  757    },
  758}
  759
  760impl MinimapVisibility {
  761    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  762        if mode.is_full() {
  763            Self::Enabled {
  764                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  765                toggle_override: false,
  766            }
  767        } else {
  768            Self::Disabled
  769        }
  770    }
  771
  772    fn hidden(&self) -> Self {
  773        match *self {
  774            Self::Enabled {
  775                setting_configuration,
  776                ..
  777            } => Self::Enabled {
  778                setting_configuration,
  779                toggle_override: setting_configuration,
  780            },
  781            Self::Disabled => Self::Disabled,
  782        }
  783    }
  784
  785    fn disabled(&self) -> bool {
  786        matches!(*self, Self::Disabled)
  787    }
  788
  789    fn settings_visibility(&self) -> bool {
  790        match *self {
  791            Self::Enabled {
  792                setting_configuration,
  793                ..
  794            } => setting_configuration,
  795            _ => false,
  796        }
  797    }
  798
  799    fn visible(&self) -> bool {
  800        match *self {
  801            Self::Enabled {
  802                setting_configuration,
  803                toggle_override,
  804            } => setting_configuration ^ toggle_override,
  805            _ => false,
  806        }
  807    }
  808
  809    fn toggle_visibility(&self) -> Self {
  810        match *self {
  811            Self::Enabled {
  812                toggle_override,
  813                setting_configuration,
  814            } => Self::Enabled {
  815                setting_configuration,
  816                toggle_override: !toggle_override,
  817            },
  818            Self::Disabled => Self::Disabled,
  819        }
  820    }
  821}
  822
  823#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  824pub enum BufferSerialization {
  825    All,
  826    NonDirtyBuffers,
  827}
  828
  829impl BufferSerialization {
  830    fn new(restore_unsaved_buffers: bool) -> Self {
  831        if restore_unsaved_buffers {
  832            Self::All
  833        } else {
  834            Self::NonDirtyBuffers
  835        }
  836    }
  837}
  838
  839#[derive(Clone, Debug)]
  840struct RunnableTasks {
  841    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  842    offset: multi_buffer::Anchor,
  843    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  844    column: u32,
  845    // Values of all named captures, including those starting with '_'
  846    extra_variables: HashMap<String, String>,
  847    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  848    context_range: Range<BufferOffset>,
  849}
  850
  851impl RunnableTasks {
  852    fn resolve<'a>(
  853        &'a self,
  854        cx: &'a task::TaskContext,
  855    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  856        self.templates.iter().filter_map(|(kind, template)| {
  857            template
  858                .resolve_task(&kind.to_id_base(), cx)
  859                .map(|task| (kind.clone(), task))
  860        })
  861    }
  862}
  863
  864#[derive(Clone)]
  865pub struct ResolvedTasks {
  866    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  867    position: Anchor,
  868}
  869
  870/// Addons allow storing per-editor state in other crates (e.g. Vim)
  871pub trait Addon: 'static {
  872    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  873
  874    fn render_buffer_header_controls(
  875        &self,
  876        _: &ExcerptInfo,
  877        _: &Window,
  878        _: &App,
  879    ) -> Option<AnyElement> {
  880        None
  881    }
  882
  883    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  884        None
  885    }
  886
  887    fn to_any(&self) -> &dyn std::any::Any;
  888
  889    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  890        None
  891    }
  892}
  893
  894struct ChangeLocation {
  895    current: Option<Vec<Anchor>>,
  896    original: Vec<Anchor>,
  897}
  898impl ChangeLocation {
  899    fn locations(&self) -> &[Anchor] {
  900        self.current.as_ref().unwrap_or(&self.original)
  901    }
  902}
  903
  904/// A set of caret positions, registered when the editor was edited.
  905pub struct ChangeList {
  906    changes: Vec<ChangeLocation>,
  907    /// Currently "selected" change.
  908    position: Option<usize>,
  909}
  910
  911impl ChangeList {
  912    pub fn new() -> Self {
  913        Self {
  914            changes: Vec::new(),
  915            position: None,
  916        }
  917    }
  918
  919    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  920    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  921    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  922        if self.changes.is_empty() {
  923            return None;
  924        }
  925
  926        let prev = self.position.unwrap_or(self.changes.len());
  927        let next = if direction == Direction::Prev {
  928            prev.saturating_sub(count)
  929        } else {
  930            (prev + count).min(self.changes.len() - 1)
  931        };
  932        self.position = Some(next);
  933        self.changes.get(next).map(|change| change.locations())
  934    }
  935
  936    /// Adds a new change to the list, resetting the change list position.
  937    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  938        self.position.take();
  939        if let Some(last) = self.changes.last_mut()
  940            && group
  941        {
  942            last.current = Some(new_positions)
  943        } else {
  944            self.changes.push(ChangeLocation {
  945                original: new_positions,
  946                current: None,
  947            });
  948        }
  949    }
  950
  951    pub fn last(&self) -> Option<&[Anchor]> {
  952        self.changes.last().map(|change| change.locations())
  953    }
  954
  955    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  956        self.changes.last().map(|change| change.original.as_slice())
  957    }
  958
  959    pub fn invert_last_group(&mut self) {
  960        if let Some(last) = self.changes.last_mut()
  961            && let Some(current) = last.current.as_mut()
  962        {
  963            mem::swap(&mut last.original, current);
  964        }
  965    }
  966}
  967
  968#[derive(Clone)]
  969struct InlineBlamePopoverState {
  970    scroll_handle: ScrollHandle,
  971    commit_message: Option<ParsedCommitMessage>,
  972    markdown: Entity<Markdown>,
  973}
  974
  975struct InlineBlamePopover {
  976    position: gpui::Point<Pixels>,
  977    hide_task: Option<Task<()>>,
  978    popover_bounds: Option<Bounds<Pixels>>,
  979    popover_state: InlineBlamePopoverState,
  980    keyboard_grace: bool,
  981}
  982
  983enum SelectionDragState {
  984    /// State when no drag related activity is detected.
  985    None,
  986    /// State when the mouse is down on a selection that is about to be dragged.
  987    ReadyToDrag {
  988        selection: Selection<Anchor>,
  989        click_position: gpui::Point<Pixels>,
  990        mouse_down_time: Instant,
  991    },
  992    /// State when the mouse is dragging the selection in the editor.
  993    Dragging {
  994        selection: Selection<Anchor>,
  995        drop_cursor: Selection<Anchor>,
  996        hide_drop_cursor: bool,
  997    },
  998}
  999
 1000enum ColumnarSelectionState {
 1001    FromMouse {
 1002        selection_tail: Anchor,
 1003        display_point: Option<DisplayPoint>,
 1004    },
 1005    FromSelection {
 1006        selection_tail: Anchor,
 1007    },
 1008}
 1009
 1010/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1011/// a breakpoint on them.
 1012#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1013struct PhantomBreakpointIndicator {
 1014    display_row: DisplayRow,
 1015    /// There's a small debounce between hovering over the line and showing the indicator.
 1016    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1017    is_active: bool,
 1018    collides_with_existing_breakpoint: bool,
 1019}
 1020
 1021/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1022///
 1023/// See the [module level documentation](self) for more information.
 1024pub struct Editor {
 1025    focus_handle: FocusHandle,
 1026    last_focused_descendant: Option<WeakFocusHandle>,
 1027    /// The text buffer being edited
 1028    buffer: Entity<MultiBuffer>,
 1029    /// Map of how text in the buffer should be displayed.
 1030    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1031    pub display_map: Entity<DisplayMap>,
 1032    placeholder_display_map: Option<Entity<DisplayMap>>,
 1033    pub selections: SelectionsCollection,
 1034    pub scroll_manager: ScrollManager,
 1035    /// When inline assist editors are linked, they all render cursors because
 1036    /// typing enters text into each of them, even the ones that aren't focused.
 1037    pub(crate) show_cursor_when_unfocused: bool,
 1038    columnar_selection_state: Option<ColumnarSelectionState>,
 1039    add_selections_state: Option<AddSelectionsState>,
 1040    select_next_state: Option<SelectNextState>,
 1041    select_prev_state: Option<SelectNextState>,
 1042    selection_history: SelectionHistory,
 1043    defer_selection_effects: bool,
 1044    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1045    autoclose_regions: Vec<AutocloseRegion>,
 1046    snippet_stack: InvalidationStack<SnippetState>,
 1047    select_syntax_node_history: SelectSyntaxNodeHistory,
 1048    ime_transaction: Option<TransactionId>,
 1049    pub diagnostics_max_severity: DiagnosticSeverity,
 1050    active_diagnostics: ActiveDiagnostic,
 1051    show_inline_diagnostics: bool,
 1052    inline_diagnostics_update: Task<()>,
 1053    inline_diagnostics_enabled: bool,
 1054    diagnostics_enabled: bool,
 1055    word_completions_enabled: bool,
 1056    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1057    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1058    hard_wrap: Option<usize>,
 1059    project: Option<Entity<Project>>,
 1060    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1061    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1062    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1063    blink_manager: Entity<BlinkManager>,
 1064    show_cursor_names: bool,
 1065    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1066    pub show_local_selections: bool,
 1067    mode: EditorMode,
 1068    show_breadcrumbs: bool,
 1069    show_gutter: bool,
 1070    show_scrollbars: ScrollbarAxes,
 1071    minimap_visibility: MinimapVisibility,
 1072    offset_content: bool,
 1073    disable_expand_excerpt_buttons: bool,
 1074    show_line_numbers: Option<bool>,
 1075    use_relative_line_numbers: Option<bool>,
 1076    show_git_diff_gutter: Option<bool>,
 1077    show_code_actions: Option<bool>,
 1078    show_runnables: Option<bool>,
 1079    show_breakpoints: Option<bool>,
 1080    show_wrap_guides: Option<bool>,
 1081    show_indent_guides: Option<bool>,
 1082    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1083    highlight_order: usize,
 1084    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1085    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1086    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1087    scrollbar_marker_state: ScrollbarMarkerState,
 1088    active_indent_guides_state: ActiveIndentGuidesState,
 1089    nav_history: Option<ItemNavHistory>,
 1090    context_menu: RefCell<Option<CodeContextMenu>>,
 1091    context_menu_options: Option<ContextMenuOptions>,
 1092    mouse_context_menu: Option<MouseContextMenu>,
 1093    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1094    inline_blame_popover: Option<InlineBlamePopover>,
 1095    inline_blame_popover_show_task: Option<Task<()>>,
 1096    signature_help_state: SignatureHelpState,
 1097    auto_signature_help: Option<bool>,
 1098    find_all_references_task_sources: Vec<Anchor>,
 1099    next_completion_id: CompletionId,
 1100    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1101    code_actions_task: Option<Task<Result<()>>>,
 1102    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1103    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1104    document_highlights_task: Option<Task<()>>,
 1105    linked_editing_range_task: Option<Task<Option<()>>>,
 1106    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1107    pending_rename: Option<RenameState>,
 1108    searchable: bool,
 1109    cursor_shape: CursorShape,
 1110    current_line_highlight: Option<CurrentLineHighlight>,
 1111    pub collapse_matches: bool,
 1112    autoindent_mode: Option<AutoindentMode>,
 1113    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1114    input_enabled: bool,
 1115    use_modal_editing: bool,
 1116    read_only: bool,
 1117    leader_id: Option<CollaboratorId>,
 1118    remote_id: Option<ViewId>,
 1119    pub hover_state: HoverState,
 1120    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1121    gutter_hovered: bool,
 1122    hovered_link_state: Option<HoveredLinkState>,
 1123    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1124    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1125    active_edit_prediction: Option<EditPredictionState>,
 1126    /// Used to prevent flickering as the user types while the menu is open
 1127    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1128    edit_prediction_settings: EditPredictionSettings,
 1129    edit_predictions_hidden_for_vim_mode: bool,
 1130    show_edit_predictions_override: Option<bool>,
 1131    show_completions_on_input_override: Option<bool>,
 1132    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1133    edit_prediction_preview: EditPredictionPreview,
 1134    edit_prediction_indent_conflict: bool,
 1135    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1136    next_inlay_id: usize,
 1137    next_color_inlay_id: usize,
 1138    _subscriptions: Vec<Subscription>,
 1139    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1140    gutter_dimensions: GutterDimensions,
 1141    style: Option<EditorStyle>,
 1142    text_style_refinement: Option<TextStyleRefinement>,
 1143    next_editor_action_id: EditorActionId,
 1144    editor_actions: Rc<
 1145        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1146    >,
 1147    use_autoclose: bool,
 1148    use_auto_surround: bool,
 1149    auto_replace_emoji_shortcode: bool,
 1150    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1151    show_git_blame_gutter: bool,
 1152    show_git_blame_inline: bool,
 1153    show_git_blame_inline_delay_task: Option<Task<()>>,
 1154    git_blame_inline_enabled: bool,
 1155    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1156    buffer_serialization: Option<BufferSerialization>,
 1157    show_selection_menu: Option<bool>,
 1158    blame: Option<Entity<GitBlame>>,
 1159    blame_subscription: Option<Subscription>,
 1160    custom_context_menu: Option<
 1161        Box<
 1162            dyn 'static
 1163                + Fn(
 1164                    &mut Self,
 1165                    DisplayPoint,
 1166                    &mut Window,
 1167                    &mut Context<Self>,
 1168                ) -> Option<Entity<ui::ContextMenu>>,
 1169        >,
 1170    >,
 1171    last_bounds: Option<Bounds<Pixels>>,
 1172    last_position_map: Option<Rc<PositionMap>>,
 1173    expect_bounds_change: Option<Bounds<Pixels>>,
 1174    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1175    tasks_update_task: Option<Task<()>>,
 1176    breakpoint_store: Option<Entity<BreakpointStore>>,
 1177    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1178    hovered_diff_hunk_row: Option<DisplayRow>,
 1179    pull_diagnostics_task: Task<()>,
 1180    pull_diagnostics_background_task: Task<()>,
 1181    in_project_search: bool,
 1182    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1183    breadcrumb_header: Option<String>,
 1184    focused_block: Option<FocusedBlock>,
 1185    next_scroll_position: NextScrollCursorCenterTopBottom,
 1186    addons: HashMap<TypeId, Box<dyn Addon>>,
 1187    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1188    load_diff_task: Option<Shared<Task<()>>>,
 1189    /// Whether we are temporarily displaying a diff other than git's
 1190    temporary_diff_override: bool,
 1191    selection_mark_mode: bool,
 1192    toggle_fold_multiple_buffers: Task<()>,
 1193    _scroll_cursor_center_top_bottom_task: Task<()>,
 1194    serialize_selections: Task<()>,
 1195    serialize_folds: Task<()>,
 1196    mouse_cursor_hidden: bool,
 1197    minimap: Option<Entity<Self>>,
 1198    hide_mouse_mode: HideMouseMode,
 1199    pub change_list: ChangeList,
 1200    inline_value_cache: InlineValueCache,
 1201
 1202    selection_drag_state: SelectionDragState,
 1203    colors: Option<LspColorData>,
 1204    post_scroll_update: Task<()>,
 1205    refresh_colors_task: Task<()>,
 1206    inlay_hints: Option<LspInlayHintData>,
 1207    folding_newlines: Task<()>,
 1208    select_next_is_case_sensitive: Option<bool>,
 1209    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1210    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1211    accent_data: Option<AccentData>,
 1212    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1213    use_base_text_line_numbers: bool,
 1214}
 1215
 1216#[derive(Debug, PartialEq)]
 1217struct AccentData {
 1218    colors: AccentColors,
 1219    overrides: Vec<SharedString>,
 1220}
 1221
 1222fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1223    if debounce_ms > 0 {
 1224        Some(Duration::from_millis(debounce_ms))
 1225    } else {
 1226        None
 1227    }
 1228}
 1229
 1230#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1231enum NextScrollCursorCenterTopBottom {
 1232    #[default]
 1233    Center,
 1234    Top,
 1235    Bottom,
 1236}
 1237
 1238impl NextScrollCursorCenterTopBottom {
 1239    fn next(&self) -> Self {
 1240        match self {
 1241            Self::Center => Self::Top,
 1242            Self::Top => Self::Bottom,
 1243            Self::Bottom => Self::Center,
 1244        }
 1245    }
 1246}
 1247
 1248#[derive(Clone)]
 1249pub struct EditorSnapshot {
 1250    pub mode: EditorMode,
 1251    show_gutter: bool,
 1252    offset_content: bool,
 1253    show_line_numbers: Option<bool>,
 1254    show_git_diff_gutter: Option<bool>,
 1255    show_code_actions: Option<bool>,
 1256    show_runnables: Option<bool>,
 1257    show_breakpoints: Option<bool>,
 1258    git_blame_gutter_max_author_length: Option<usize>,
 1259    pub display_snapshot: DisplaySnapshot,
 1260    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1261    is_focused: bool,
 1262    scroll_anchor: ScrollAnchor,
 1263    ongoing_scroll: OngoingScroll,
 1264    current_line_highlight: CurrentLineHighlight,
 1265    gutter_hovered: bool,
 1266}
 1267
 1268#[derive(Default, Debug, Clone, Copy)]
 1269pub struct GutterDimensions {
 1270    pub left_padding: Pixels,
 1271    pub right_padding: Pixels,
 1272    pub width: Pixels,
 1273    pub margin: Pixels,
 1274    pub git_blame_entries_width: Option<Pixels>,
 1275}
 1276
 1277impl GutterDimensions {
 1278    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1279        Self {
 1280            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1281            ..Default::default()
 1282        }
 1283    }
 1284
 1285    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1286        -cx.text_system().descent(font_id, font_size)
 1287    }
 1288    /// The full width of the space taken up by the gutter.
 1289    pub fn full_width(&self) -> Pixels {
 1290        self.margin + self.width
 1291    }
 1292
 1293    /// The width of the space reserved for the fold indicators,
 1294    /// use alongside 'justify_end' and `gutter_width` to
 1295    /// right align content with the line numbers
 1296    pub fn fold_area_width(&self) -> Pixels {
 1297        self.margin + self.right_padding
 1298    }
 1299}
 1300
 1301struct CharacterDimensions {
 1302    em_width: Pixels,
 1303    em_advance: Pixels,
 1304    line_height: Pixels,
 1305}
 1306
 1307#[derive(Debug)]
 1308pub struct RemoteSelection {
 1309    pub replica_id: ReplicaId,
 1310    pub selection: Selection<Anchor>,
 1311    pub cursor_shape: CursorShape,
 1312    pub collaborator_id: CollaboratorId,
 1313    pub line_mode: bool,
 1314    pub user_name: Option<SharedString>,
 1315    pub color: PlayerColor,
 1316}
 1317
 1318#[derive(Clone, Debug)]
 1319struct SelectionHistoryEntry {
 1320    selections: Arc<[Selection<Anchor>]>,
 1321    select_next_state: Option<SelectNextState>,
 1322    select_prev_state: Option<SelectNextState>,
 1323    add_selections_state: Option<AddSelectionsState>,
 1324}
 1325
 1326#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1327enum SelectionHistoryMode {
 1328    #[default]
 1329    Normal,
 1330    Undoing,
 1331    Redoing,
 1332    Skipping,
 1333}
 1334
 1335#[derive(Clone, PartialEq, Eq, Hash)]
 1336struct HoveredCursor {
 1337    replica_id: ReplicaId,
 1338    selection_id: usize,
 1339}
 1340
 1341#[derive(Debug)]
 1342/// SelectionEffects controls the side-effects of updating the selection.
 1343///
 1344/// The default behaviour does "what you mostly want":
 1345/// - it pushes to the nav history if the cursor moved by >10 lines
 1346/// - it re-triggers completion requests
 1347/// - it scrolls to fit
 1348///
 1349/// You might want to modify these behaviours. For example when doing a "jump"
 1350/// like go to definition, we always want to add to nav history; but when scrolling
 1351/// in vim mode we never do.
 1352///
 1353/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1354/// move.
 1355#[derive(Clone)]
 1356pub struct SelectionEffects {
 1357    nav_history: Option<bool>,
 1358    completions: bool,
 1359    scroll: Option<Autoscroll>,
 1360}
 1361
 1362impl Default for SelectionEffects {
 1363    fn default() -> Self {
 1364        Self {
 1365            nav_history: None,
 1366            completions: true,
 1367            scroll: Some(Autoscroll::fit()),
 1368        }
 1369    }
 1370}
 1371impl SelectionEffects {
 1372    pub fn scroll(scroll: Autoscroll) -> Self {
 1373        Self {
 1374            scroll: Some(scroll),
 1375            ..Default::default()
 1376        }
 1377    }
 1378
 1379    pub fn no_scroll() -> Self {
 1380        Self {
 1381            scroll: None,
 1382            ..Default::default()
 1383        }
 1384    }
 1385
 1386    pub fn completions(self, completions: bool) -> Self {
 1387        Self {
 1388            completions,
 1389            ..self
 1390        }
 1391    }
 1392
 1393    pub fn nav_history(self, nav_history: bool) -> Self {
 1394        Self {
 1395            nav_history: Some(nav_history),
 1396            ..self
 1397        }
 1398    }
 1399}
 1400
 1401struct DeferredSelectionEffectsState {
 1402    changed: bool,
 1403    effects: SelectionEffects,
 1404    old_cursor_position: Anchor,
 1405    history_entry: SelectionHistoryEntry,
 1406}
 1407
 1408#[derive(Default)]
 1409struct SelectionHistory {
 1410    #[allow(clippy::type_complexity)]
 1411    selections_by_transaction:
 1412        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1413    mode: SelectionHistoryMode,
 1414    undo_stack: VecDeque<SelectionHistoryEntry>,
 1415    redo_stack: VecDeque<SelectionHistoryEntry>,
 1416}
 1417
 1418impl SelectionHistory {
 1419    #[track_caller]
 1420    fn insert_transaction(
 1421        &mut self,
 1422        transaction_id: TransactionId,
 1423        selections: Arc<[Selection<Anchor>]>,
 1424    ) {
 1425        if selections.is_empty() {
 1426            log::error!(
 1427                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1428                std::panic::Location::caller()
 1429            );
 1430            return;
 1431        }
 1432        self.selections_by_transaction
 1433            .insert(transaction_id, (selections, None));
 1434    }
 1435
 1436    #[allow(clippy::type_complexity)]
 1437    fn transaction(
 1438        &self,
 1439        transaction_id: TransactionId,
 1440    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1441        self.selections_by_transaction.get(&transaction_id)
 1442    }
 1443
 1444    #[allow(clippy::type_complexity)]
 1445    fn transaction_mut(
 1446        &mut self,
 1447        transaction_id: TransactionId,
 1448    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1449        self.selections_by_transaction.get_mut(&transaction_id)
 1450    }
 1451
 1452    fn push(&mut self, entry: SelectionHistoryEntry) {
 1453        if !entry.selections.is_empty() {
 1454            match self.mode {
 1455                SelectionHistoryMode::Normal => {
 1456                    self.push_undo(entry);
 1457                    self.redo_stack.clear();
 1458                }
 1459                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1460                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1461                SelectionHistoryMode::Skipping => {}
 1462            }
 1463        }
 1464    }
 1465
 1466    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1467        if self
 1468            .undo_stack
 1469            .back()
 1470            .is_none_or(|e| e.selections != entry.selections)
 1471        {
 1472            self.undo_stack.push_back(entry);
 1473            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1474                self.undo_stack.pop_front();
 1475            }
 1476        }
 1477    }
 1478
 1479    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1480        if self
 1481            .redo_stack
 1482            .back()
 1483            .is_none_or(|e| e.selections != entry.selections)
 1484        {
 1485            self.redo_stack.push_back(entry);
 1486            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1487                self.redo_stack.pop_front();
 1488            }
 1489        }
 1490    }
 1491}
 1492
 1493#[derive(Clone, Copy)]
 1494pub struct RowHighlightOptions {
 1495    pub autoscroll: bool,
 1496    pub include_gutter: bool,
 1497}
 1498
 1499impl Default for RowHighlightOptions {
 1500    fn default() -> Self {
 1501        Self {
 1502            autoscroll: Default::default(),
 1503            include_gutter: true,
 1504        }
 1505    }
 1506}
 1507
 1508struct RowHighlight {
 1509    index: usize,
 1510    range: Range<Anchor>,
 1511    color: Hsla,
 1512    options: RowHighlightOptions,
 1513    type_id: TypeId,
 1514}
 1515
 1516#[derive(Clone, Debug)]
 1517struct AddSelectionsState {
 1518    groups: Vec<AddSelectionsGroup>,
 1519}
 1520
 1521#[derive(Clone, Debug)]
 1522struct AddSelectionsGroup {
 1523    above: bool,
 1524    stack: Vec<usize>,
 1525}
 1526
 1527#[derive(Clone)]
 1528struct SelectNextState {
 1529    query: AhoCorasick,
 1530    wordwise: bool,
 1531    done: bool,
 1532}
 1533
 1534impl std::fmt::Debug for SelectNextState {
 1535    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1536        f.debug_struct(std::any::type_name::<Self>())
 1537            .field("wordwise", &self.wordwise)
 1538            .field("done", &self.done)
 1539            .finish()
 1540    }
 1541}
 1542
 1543#[derive(Debug)]
 1544struct AutocloseRegion {
 1545    selection_id: usize,
 1546    range: Range<Anchor>,
 1547    pair: BracketPair,
 1548}
 1549
 1550#[derive(Debug)]
 1551struct SnippetState {
 1552    ranges: Vec<Vec<Range<Anchor>>>,
 1553    active_index: usize,
 1554    choices: Vec<Option<Vec<String>>>,
 1555}
 1556
 1557#[doc(hidden)]
 1558pub struct RenameState {
 1559    pub range: Range<Anchor>,
 1560    pub old_name: Arc<str>,
 1561    pub editor: Entity<Editor>,
 1562    block_id: CustomBlockId,
 1563}
 1564
 1565struct InvalidationStack<T>(Vec<T>);
 1566
 1567struct RegisteredEditPredictionDelegate {
 1568    provider: Arc<dyn EditPredictionDelegateHandle>,
 1569    _subscription: Subscription,
 1570}
 1571
 1572#[derive(Debug, PartialEq, Eq)]
 1573pub struct ActiveDiagnosticGroup {
 1574    pub active_range: Range<Anchor>,
 1575    pub active_message: String,
 1576    pub group_id: usize,
 1577    pub blocks: HashSet<CustomBlockId>,
 1578}
 1579
 1580#[derive(Debug, PartialEq, Eq)]
 1581
 1582pub(crate) enum ActiveDiagnostic {
 1583    None,
 1584    All,
 1585    Group(ActiveDiagnosticGroup),
 1586}
 1587
 1588#[derive(Serialize, Deserialize, Clone, Debug)]
 1589pub struct ClipboardSelection {
 1590    /// The number of bytes in this selection.
 1591    pub len: usize,
 1592    /// Whether this was a full-line selection.
 1593    pub is_entire_line: bool,
 1594    /// The indentation of the first line when this content was originally copied.
 1595    pub first_line_indent: u32,
 1596    #[serde(default)]
 1597    pub file_path: Option<PathBuf>,
 1598    #[serde(default)]
 1599    pub line_range: Option<RangeInclusive<u32>>,
 1600}
 1601
 1602impl ClipboardSelection {
 1603    pub fn for_buffer(
 1604        len: usize,
 1605        is_entire_line: bool,
 1606        range: Range<Point>,
 1607        buffer: &MultiBufferSnapshot,
 1608        project: Option<&Entity<Project>>,
 1609        cx: &App,
 1610    ) -> Self {
 1611        let first_line_indent = buffer
 1612            .indent_size_for_line(MultiBufferRow(range.start.row))
 1613            .len;
 1614
 1615        let file_path = util::maybe!({
 1616            let project = project?.read(cx);
 1617            let file = buffer.file_at(range.start)?;
 1618            let project_path = ProjectPath {
 1619                worktree_id: file.worktree_id(cx),
 1620                path: file.path().clone(),
 1621            };
 1622            project.absolute_path(&project_path, cx)
 1623        });
 1624
 1625        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1626
 1627        Self {
 1628            len,
 1629            is_entire_line,
 1630            first_line_indent,
 1631            file_path,
 1632            line_range,
 1633        }
 1634    }
 1635}
 1636
 1637// selections, scroll behavior, was newest selection reversed
 1638type SelectSyntaxNodeHistoryState = (
 1639    Box<[Selection<MultiBufferOffset>]>,
 1640    SelectSyntaxNodeScrollBehavior,
 1641    bool,
 1642);
 1643
 1644#[derive(Default)]
 1645struct SelectSyntaxNodeHistory {
 1646    stack: Vec<SelectSyntaxNodeHistoryState>,
 1647    // disable temporarily to allow changing selections without losing the stack
 1648    pub disable_clearing: bool,
 1649}
 1650
 1651impl SelectSyntaxNodeHistory {
 1652    pub fn try_clear(&mut self) {
 1653        if !self.disable_clearing {
 1654            self.stack.clear();
 1655        }
 1656    }
 1657
 1658    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1659        self.stack.push(selection);
 1660    }
 1661
 1662    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1663        self.stack.pop()
 1664    }
 1665}
 1666
 1667enum SelectSyntaxNodeScrollBehavior {
 1668    CursorTop,
 1669    FitSelection,
 1670    CursorBottom,
 1671}
 1672
 1673#[derive(Debug)]
 1674pub(crate) struct NavigationData {
 1675    cursor_anchor: Anchor,
 1676    cursor_position: Point,
 1677    scroll_anchor: ScrollAnchor,
 1678    scroll_top_row: u32,
 1679}
 1680
 1681#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1682pub enum GotoDefinitionKind {
 1683    Symbol,
 1684    Declaration,
 1685    Type,
 1686    Implementation,
 1687}
 1688
 1689pub enum FormatTarget {
 1690    Buffers(HashSet<Entity<Buffer>>),
 1691    Ranges(Vec<Range<MultiBufferPoint>>),
 1692}
 1693
 1694pub(crate) struct FocusedBlock {
 1695    id: BlockId,
 1696    focus_handle: WeakFocusHandle,
 1697}
 1698
 1699#[derive(Clone, Debug)]
 1700enum JumpData {
 1701    MultiBufferRow {
 1702        row: MultiBufferRow,
 1703        line_offset_from_top: u32,
 1704    },
 1705    MultiBufferPoint {
 1706        excerpt_id: ExcerptId,
 1707        position: Point,
 1708        anchor: text::Anchor,
 1709        line_offset_from_top: u32,
 1710    },
 1711}
 1712
 1713pub enum MultibufferSelectionMode {
 1714    First,
 1715    All,
 1716}
 1717
 1718#[derive(Clone, Copy, Debug, Default)]
 1719pub struct RewrapOptions {
 1720    pub override_language_settings: bool,
 1721    pub preserve_existing_whitespace: bool,
 1722}
 1723
 1724impl Editor {
 1725    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1726        let buffer = cx.new(|cx| Buffer::local("", cx));
 1727        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1728        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1729    }
 1730
 1731    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1732        let buffer = cx.new(|cx| Buffer::local("", cx));
 1733        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1734        Self::new(EditorMode::full(), buffer, None, window, cx)
 1735    }
 1736
 1737    pub fn auto_height(
 1738        min_lines: usize,
 1739        max_lines: usize,
 1740        window: &mut Window,
 1741        cx: &mut Context<Self>,
 1742    ) -> Self {
 1743        let buffer = cx.new(|cx| Buffer::local("", cx));
 1744        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1745        Self::new(
 1746            EditorMode::AutoHeight {
 1747                min_lines,
 1748                max_lines: Some(max_lines),
 1749            },
 1750            buffer,
 1751            None,
 1752            window,
 1753            cx,
 1754        )
 1755    }
 1756
 1757    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1758    /// The editor grows as tall as needed to fit its content.
 1759    pub fn auto_height_unbounded(
 1760        min_lines: usize,
 1761        window: &mut Window,
 1762        cx: &mut Context<Self>,
 1763    ) -> Self {
 1764        let buffer = cx.new(|cx| Buffer::local("", cx));
 1765        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1766        Self::new(
 1767            EditorMode::AutoHeight {
 1768                min_lines,
 1769                max_lines: None,
 1770            },
 1771            buffer,
 1772            None,
 1773            window,
 1774            cx,
 1775        )
 1776    }
 1777
 1778    pub fn for_buffer(
 1779        buffer: Entity<Buffer>,
 1780        project: Option<Entity<Project>>,
 1781        window: &mut Window,
 1782        cx: &mut Context<Self>,
 1783    ) -> Self {
 1784        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1785        Self::new(EditorMode::full(), buffer, project, window, cx)
 1786    }
 1787
 1788    pub fn for_multibuffer(
 1789        buffer: Entity<MultiBuffer>,
 1790        project: Option<Entity<Project>>,
 1791        window: &mut Window,
 1792        cx: &mut Context<Self>,
 1793    ) -> Self {
 1794        Self::new(EditorMode::full(), buffer, project, window, cx)
 1795    }
 1796
 1797    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1798        let mut clone = Self::new(
 1799            self.mode.clone(),
 1800            self.buffer.clone(),
 1801            self.project.clone(),
 1802            window,
 1803            cx,
 1804        );
 1805        self.display_map.update(cx, |display_map, cx| {
 1806            let snapshot = display_map.snapshot(cx);
 1807            clone.display_map.update(cx, |display_map, cx| {
 1808                display_map.set_state(&snapshot, cx);
 1809            });
 1810        });
 1811        clone.folds_did_change(cx);
 1812        clone.selections.clone_state(&self.selections);
 1813        clone.scroll_manager.clone_state(&self.scroll_manager);
 1814        clone.searchable = self.searchable;
 1815        clone.read_only = self.read_only;
 1816        clone
 1817    }
 1818
 1819    pub fn new(
 1820        mode: EditorMode,
 1821        buffer: Entity<MultiBuffer>,
 1822        project: Option<Entity<Project>>,
 1823        window: &mut Window,
 1824        cx: &mut Context<Self>,
 1825    ) -> Self {
 1826        Editor::new_internal(mode, buffer, project, None, window, cx)
 1827    }
 1828
 1829    pub fn sticky_headers(
 1830        &self,
 1831        style: &EditorStyle,
 1832        cx: &App,
 1833    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1834        let multi_buffer = self.buffer().read(cx);
 1835        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1836        let multi_buffer_visible_start = self
 1837            .scroll_manager
 1838            .anchor()
 1839            .anchor
 1840            .to_point(&multi_buffer_snapshot);
 1841        let max_row = multi_buffer_snapshot.max_point().row;
 1842
 1843        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1844        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1845
 1846        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1847            let outline_items = buffer
 1848                .outline_items_containing(
 1849                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1850                    true,
 1851                    Some(style.syntax.as_ref()),
 1852                )
 1853                .into_iter()
 1854                .map(|outline_item| OutlineItem {
 1855                    depth: outline_item.depth,
 1856                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1857                    source_range_for_text: Anchor::range_in_buffer(
 1858                        *excerpt_id,
 1859                        outline_item.source_range_for_text,
 1860                    ),
 1861                    text: outline_item.text,
 1862                    highlight_ranges: outline_item.highlight_ranges,
 1863                    name_ranges: outline_item.name_ranges,
 1864                    body_range: outline_item
 1865                        .body_range
 1866                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1867                    annotation_range: outline_item
 1868                        .annotation_range
 1869                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1870                });
 1871            return Some(outline_items.collect());
 1872        }
 1873
 1874        None
 1875    }
 1876
 1877    fn new_internal(
 1878        mode: EditorMode,
 1879        multi_buffer: Entity<MultiBuffer>,
 1880        project: Option<Entity<Project>>,
 1881        display_map: Option<Entity<DisplayMap>>,
 1882        window: &mut Window,
 1883        cx: &mut Context<Self>,
 1884    ) -> Self {
 1885        debug_assert!(
 1886            display_map.is_none() || mode.is_minimap(),
 1887            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1888        );
 1889
 1890        let full_mode = mode.is_full();
 1891        let is_minimap = mode.is_minimap();
 1892        let diagnostics_max_severity = if full_mode {
 1893            EditorSettings::get_global(cx)
 1894                .diagnostics_max_severity
 1895                .unwrap_or(DiagnosticSeverity::Hint)
 1896        } else {
 1897            DiagnosticSeverity::Off
 1898        };
 1899        let style = window.text_style();
 1900        let font_size = style.font_size.to_pixels(window.rem_size());
 1901        let editor = cx.entity().downgrade();
 1902        let fold_placeholder = FoldPlaceholder {
 1903            constrain_width: false,
 1904            render: Arc::new(move |fold_id, fold_range, cx| {
 1905                let editor = editor.clone();
 1906                div()
 1907                    .id(fold_id)
 1908                    .bg(cx.theme().colors().ghost_element_background)
 1909                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1910                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1911                    .rounded_xs()
 1912                    .size_full()
 1913                    .cursor_pointer()
 1914                    .child("")
 1915                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1916                    .on_click(move |_, _window, cx| {
 1917                        editor
 1918                            .update(cx, |editor, cx| {
 1919                                editor.unfold_ranges(
 1920                                    &[fold_range.start..fold_range.end],
 1921                                    true,
 1922                                    false,
 1923                                    cx,
 1924                                );
 1925                                cx.stop_propagation();
 1926                            })
 1927                            .ok();
 1928                    })
 1929                    .into_any()
 1930            }),
 1931            merge_adjacent: true,
 1932            ..FoldPlaceholder::default()
 1933        };
 1934        let display_map = display_map.unwrap_or_else(|| {
 1935            cx.new(|cx| {
 1936                DisplayMap::new(
 1937                    multi_buffer.clone(),
 1938                    style.font(),
 1939                    font_size,
 1940                    None,
 1941                    FILE_HEADER_HEIGHT,
 1942                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1943                    fold_placeholder,
 1944                    diagnostics_max_severity,
 1945                    cx,
 1946                )
 1947            })
 1948        });
 1949
 1950        let selections = SelectionsCollection::new();
 1951
 1952        let blink_manager = cx.new(|cx| {
 1953            let mut blink_manager = BlinkManager::new(
 1954                CURSOR_BLINK_INTERVAL,
 1955                |cx| EditorSettings::get_global(cx).cursor_blink,
 1956                cx,
 1957            );
 1958            if is_minimap {
 1959                blink_manager.disable(cx);
 1960            }
 1961            blink_manager
 1962        });
 1963
 1964        let soft_wrap_mode_override =
 1965            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1966
 1967        let mut project_subscriptions = Vec::new();
 1968        if full_mode && let Some(project) = project.as_ref() {
 1969            project_subscriptions.push(cx.subscribe_in(
 1970                project,
 1971                window,
 1972                |editor, _, event, window, cx| match event {
 1973                    project::Event::RefreshCodeLens => {
 1974                        // we always query lens with actions, without storing them, always refreshing them
 1975                    }
 1976                    project::Event::RefreshInlayHints {
 1977                        server_id,
 1978                        request_id,
 1979                    } => {
 1980                        editor.refresh_inlay_hints(
 1981                            InlayHintRefreshReason::RefreshRequested {
 1982                                server_id: *server_id,
 1983                                request_id: *request_id,
 1984                            },
 1985                            cx,
 1986                        );
 1987                    }
 1988                    project::Event::LanguageServerRemoved(..) => {
 1989                        if editor.tasks_update_task.is_none() {
 1990                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1991                        }
 1992                        editor.registered_buffers.clear();
 1993                        editor.register_visible_buffers(cx);
 1994                    }
 1995                    project::Event::LanguageServerAdded(..) => {
 1996                        if editor.tasks_update_task.is_none() {
 1997                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1998                        }
 1999                    }
 2000                    project::Event::SnippetEdit(id, snippet_edits) => {
 2001                        // todo(lw): Non singletons
 2002                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2003                            let snapshot = buffer.read(cx).snapshot();
 2004                            let focus_handle = editor.focus_handle(cx);
 2005                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2006                                for (range, snippet) in snippet_edits {
 2007                                    let buffer_range =
 2008                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2009                                    editor
 2010                                        .insert_snippet(
 2011                                            &[MultiBufferOffset(buffer_range.start)
 2012                                                ..MultiBufferOffset(buffer_range.end)],
 2013                                            snippet.clone(),
 2014                                            window,
 2015                                            cx,
 2016                                        )
 2017                                        .ok();
 2018                                }
 2019                            }
 2020                        }
 2021                    }
 2022                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2023                        let buffer_id = *buffer_id;
 2024                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2025                            editor.register_buffer(buffer_id, cx);
 2026                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2027                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2028                            refresh_linked_ranges(editor, window, cx);
 2029                            editor.refresh_code_actions(window, cx);
 2030                            editor.refresh_document_highlights(cx);
 2031                        }
 2032                    }
 2033
 2034                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2035                        let Some(workspace) = editor.workspace() else {
 2036                            return;
 2037                        };
 2038                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2039                        else {
 2040                            return;
 2041                        };
 2042
 2043                        if active_editor.entity_id() == cx.entity_id() {
 2044                            let entity_id = cx.entity_id();
 2045                            workspace.update(cx, |this, cx| {
 2046                                this.panes_mut()
 2047                                    .iter_mut()
 2048                                    .filter(|pane| pane.entity_id() != entity_id)
 2049                                    .for_each(|p| {
 2050                                        p.update(cx, |pane, _| {
 2051                                            pane.nav_history_mut().rename_item(
 2052                                                entity_id,
 2053                                                project_path.clone(),
 2054                                                abs_path.clone().into(),
 2055                                            );
 2056                                        })
 2057                                    });
 2058                            });
 2059                            let edited_buffers_already_open = {
 2060                                let other_editors: Vec<Entity<Editor>> = workspace
 2061                                    .read(cx)
 2062                                    .panes()
 2063                                    .iter()
 2064                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 2065                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2066                                    .collect();
 2067
 2068                                transaction.0.keys().all(|buffer| {
 2069                                    other_editors.iter().any(|editor| {
 2070                                        let multi_buffer = editor.read(cx).buffer();
 2071                                        multi_buffer.read(cx).is_singleton()
 2072                                            && multi_buffer.read(cx).as_singleton().map_or(
 2073                                                false,
 2074                                                |singleton| {
 2075                                                    singleton.entity_id() == buffer.entity_id()
 2076                                                },
 2077                                            )
 2078                                    })
 2079                                })
 2080                            };
 2081                            if !edited_buffers_already_open {
 2082                                let workspace = workspace.downgrade();
 2083                                let transaction = transaction.clone();
 2084                                cx.defer_in(window, move |_, window, cx| {
 2085                                    cx.spawn_in(window, async move |editor, cx| {
 2086                                        Self::open_project_transaction(
 2087                                            &editor,
 2088                                            workspace,
 2089                                            transaction,
 2090                                            "Rename".to_string(),
 2091                                            cx,
 2092                                        )
 2093                                        .await
 2094                                        .ok()
 2095                                    })
 2096                                    .detach();
 2097                                });
 2098                            }
 2099                        }
 2100                    }
 2101
 2102                    _ => {}
 2103                },
 2104            ));
 2105            if let Some(task_inventory) = project
 2106                .read(cx)
 2107                .task_store()
 2108                .read(cx)
 2109                .task_inventory()
 2110                .cloned()
 2111            {
 2112                project_subscriptions.push(cx.observe_in(
 2113                    &task_inventory,
 2114                    window,
 2115                    |editor, _, window, cx| {
 2116                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2117                    },
 2118                ));
 2119            };
 2120
 2121            project_subscriptions.push(cx.subscribe_in(
 2122                &project.read(cx).breakpoint_store(),
 2123                window,
 2124                |editor, _, event, window, cx| match event {
 2125                    BreakpointStoreEvent::ClearDebugLines => {
 2126                        editor.clear_row_highlights::<ActiveDebugLine>();
 2127                        editor.refresh_inline_values(cx);
 2128                    }
 2129                    BreakpointStoreEvent::SetDebugLine => {
 2130                        if editor.go_to_active_debug_line(window, cx) {
 2131                            cx.stop_propagation();
 2132                        }
 2133
 2134                        editor.refresh_inline_values(cx);
 2135                    }
 2136                    _ => {}
 2137                },
 2138            ));
 2139            let git_store = project.read(cx).git_store().clone();
 2140            let project = project.clone();
 2141            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2142                if let GitStoreEvent::RepositoryAdded = event {
 2143                    this.load_diff_task = Some(
 2144                        update_uncommitted_diff_for_buffer(
 2145                            cx.entity(),
 2146                            &project,
 2147                            this.buffer.read(cx).all_buffers(),
 2148                            this.buffer.clone(),
 2149                            cx,
 2150                        )
 2151                        .shared(),
 2152                    );
 2153                }
 2154            }));
 2155        }
 2156
 2157        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2158
 2159        let inlay_hint_settings =
 2160            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2161        let focus_handle = cx.focus_handle();
 2162        if !is_minimap {
 2163            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2164                .detach();
 2165            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2166                .detach();
 2167            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2168                .detach();
 2169            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2170                .detach();
 2171            cx.observe_pending_input(window, Self::observe_pending_input)
 2172                .detach();
 2173        }
 2174
 2175        let show_indent_guides =
 2176            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2177                Some(false)
 2178            } else {
 2179                None
 2180            };
 2181
 2182        let breakpoint_store = match (&mode, project.as_ref()) {
 2183            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2184            _ => None,
 2185        };
 2186
 2187        let mut code_action_providers = Vec::new();
 2188        let mut load_uncommitted_diff = None;
 2189        if let Some(project) = project.clone() {
 2190            load_uncommitted_diff = Some(
 2191                update_uncommitted_diff_for_buffer(
 2192                    cx.entity(),
 2193                    &project,
 2194                    multi_buffer.read(cx).all_buffers(),
 2195                    multi_buffer.clone(),
 2196                    cx,
 2197                )
 2198                .shared(),
 2199            );
 2200            code_action_providers.push(Rc::new(project) as Rc<_>);
 2201        }
 2202
 2203        let mut editor = Self {
 2204            focus_handle,
 2205            show_cursor_when_unfocused: false,
 2206            last_focused_descendant: None,
 2207            buffer: multi_buffer.clone(),
 2208            display_map: display_map.clone(),
 2209            placeholder_display_map: None,
 2210            selections,
 2211            scroll_manager: ScrollManager::new(cx),
 2212            columnar_selection_state: None,
 2213            add_selections_state: None,
 2214            select_next_state: None,
 2215            select_prev_state: None,
 2216            selection_history: SelectionHistory::default(),
 2217            defer_selection_effects: false,
 2218            deferred_selection_effects_state: None,
 2219            autoclose_regions: Vec::new(),
 2220            snippet_stack: InvalidationStack::default(),
 2221            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2222            ime_transaction: None,
 2223            active_diagnostics: ActiveDiagnostic::None,
 2224            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2225            inline_diagnostics_update: Task::ready(()),
 2226            inline_diagnostics: Vec::new(),
 2227            soft_wrap_mode_override,
 2228            diagnostics_max_severity,
 2229            hard_wrap: None,
 2230            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2231            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2232            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2233            project,
 2234            blink_manager: blink_manager.clone(),
 2235            show_local_selections: true,
 2236            show_scrollbars: ScrollbarAxes {
 2237                horizontal: full_mode,
 2238                vertical: full_mode,
 2239            },
 2240            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2241            offset_content: !matches!(mode, EditorMode::SingleLine),
 2242            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2243            show_gutter: full_mode,
 2244            show_line_numbers: (!full_mode).then_some(false),
 2245            use_relative_line_numbers: None,
 2246            disable_expand_excerpt_buttons: !full_mode,
 2247            show_git_diff_gutter: None,
 2248            show_code_actions: None,
 2249            show_runnables: None,
 2250            show_breakpoints: None,
 2251            show_wrap_guides: None,
 2252            show_indent_guides,
 2253            buffers_with_disabled_indent_guides: HashSet::default(),
 2254            highlight_order: 0,
 2255            highlighted_rows: HashMap::default(),
 2256            background_highlights: HashMap::default(),
 2257            gutter_highlights: HashMap::default(),
 2258            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2259            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2260            nav_history: None,
 2261            context_menu: RefCell::new(None),
 2262            context_menu_options: None,
 2263            mouse_context_menu: None,
 2264            completion_tasks: Vec::new(),
 2265            inline_blame_popover: None,
 2266            inline_blame_popover_show_task: None,
 2267            signature_help_state: SignatureHelpState::default(),
 2268            auto_signature_help: None,
 2269            find_all_references_task_sources: Vec::new(),
 2270            next_completion_id: 0,
 2271            next_inlay_id: 0,
 2272            code_action_providers,
 2273            available_code_actions: None,
 2274            code_actions_task: None,
 2275            quick_selection_highlight_task: None,
 2276            debounced_selection_highlight_task: None,
 2277            document_highlights_task: None,
 2278            linked_editing_range_task: None,
 2279            pending_rename: None,
 2280            searchable: !is_minimap,
 2281            cursor_shape: EditorSettings::get_global(cx)
 2282                .cursor_shape
 2283                .unwrap_or_default(),
 2284            current_line_highlight: None,
 2285            autoindent_mode: Some(AutoindentMode::EachLine),
 2286            collapse_matches: false,
 2287            workspace: None,
 2288            input_enabled: !is_minimap,
 2289            use_modal_editing: full_mode,
 2290            read_only: is_minimap,
 2291            use_autoclose: true,
 2292            use_auto_surround: true,
 2293            auto_replace_emoji_shortcode: false,
 2294            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2295            leader_id: None,
 2296            remote_id: None,
 2297            hover_state: HoverState::default(),
 2298            pending_mouse_down: None,
 2299            hovered_link_state: None,
 2300            edit_prediction_provider: None,
 2301            active_edit_prediction: None,
 2302            stale_edit_prediction_in_menu: None,
 2303            edit_prediction_preview: EditPredictionPreview::Inactive {
 2304                released_too_fast: false,
 2305            },
 2306            inline_diagnostics_enabled: full_mode,
 2307            diagnostics_enabled: full_mode,
 2308            word_completions_enabled: full_mode,
 2309            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2310            gutter_hovered: false,
 2311            pixel_position_of_newest_cursor: None,
 2312            last_bounds: None,
 2313            last_position_map: None,
 2314            expect_bounds_change: None,
 2315            gutter_dimensions: GutterDimensions::default(),
 2316            style: None,
 2317            show_cursor_names: false,
 2318            hovered_cursors: HashMap::default(),
 2319            next_editor_action_id: EditorActionId::default(),
 2320            editor_actions: Rc::default(),
 2321            edit_predictions_hidden_for_vim_mode: false,
 2322            show_edit_predictions_override: None,
 2323            show_completions_on_input_override: None,
 2324            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2325            edit_prediction_settings: EditPredictionSettings::Disabled,
 2326            edit_prediction_indent_conflict: false,
 2327            edit_prediction_requires_modifier_in_indent_conflict: true,
 2328            custom_context_menu: None,
 2329            show_git_blame_gutter: false,
 2330            show_git_blame_inline: false,
 2331            show_selection_menu: None,
 2332            show_git_blame_inline_delay_task: None,
 2333            git_blame_inline_enabled: full_mode
 2334                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2335            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2336            buffer_serialization: is_minimap.not().then(|| {
 2337                BufferSerialization::new(
 2338                    ProjectSettings::get_global(cx)
 2339                        .session
 2340                        .restore_unsaved_buffers,
 2341                )
 2342            }),
 2343            blame: None,
 2344            blame_subscription: None,
 2345            tasks: BTreeMap::default(),
 2346
 2347            breakpoint_store,
 2348            gutter_breakpoint_indicator: (None, None),
 2349            hovered_diff_hunk_row: None,
 2350            _subscriptions: (!is_minimap)
 2351                .then(|| {
 2352                    vec![
 2353                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2354                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2355                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2356                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2357                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2358                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2359                        cx.observe_window_activation(window, |editor, window, cx| {
 2360                            let active = window.is_window_active();
 2361                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2362                                if active {
 2363                                    blink_manager.enable(cx);
 2364                                } else {
 2365                                    blink_manager.disable(cx);
 2366                                }
 2367                            });
 2368                            if active {
 2369                                editor.show_mouse_cursor(cx);
 2370                            }
 2371                        }),
 2372                    ]
 2373                })
 2374                .unwrap_or_default(),
 2375            tasks_update_task: None,
 2376            pull_diagnostics_task: Task::ready(()),
 2377            pull_diagnostics_background_task: Task::ready(()),
 2378            colors: None,
 2379            refresh_colors_task: Task::ready(()),
 2380            inlay_hints: None,
 2381            next_color_inlay_id: 0,
 2382            post_scroll_update: Task::ready(()),
 2383            linked_edit_ranges: Default::default(),
 2384            in_project_search: false,
 2385            previous_search_ranges: None,
 2386            breadcrumb_header: None,
 2387            focused_block: None,
 2388            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2389            addons: HashMap::default(),
 2390            registered_buffers: HashMap::default(),
 2391            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2392            selection_mark_mode: false,
 2393            toggle_fold_multiple_buffers: Task::ready(()),
 2394            serialize_selections: Task::ready(()),
 2395            serialize_folds: Task::ready(()),
 2396            text_style_refinement: None,
 2397            load_diff_task: load_uncommitted_diff,
 2398            temporary_diff_override: false,
 2399            mouse_cursor_hidden: false,
 2400            minimap: None,
 2401            hide_mouse_mode: EditorSettings::get_global(cx)
 2402                .hide_mouse
 2403                .unwrap_or_default(),
 2404            change_list: ChangeList::new(),
 2405            mode,
 2406            selection_drag_state: SelectionDragState::None,
 2407            folding_newlines: Task::ready(()),
 2408            lookup_key: None,
 2409            select_next_is_case_sensitive: None,
 2410            applicable_language_settings: HashMap::default(),
 2411            accent_data: None,
 2412            fetched_tree_sitter_chunks: HashMap::default(),
 2413            use_base_text_line_numbers: false,
 2414        };
 2415
 2416        if is_minimap {
 2417            return editor;
 2418        }
 2419
 2420        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2421        editor.accent_data = editor.fetch_accent_data(cx);
 2422
 2423        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2424            editor
 2425                ._subscriptions
 2426                .push(cx.observe(breakpoints, |_, _, cx| {
 2427                    cx.notify();
 2428                }));
 2429        }
 2430        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2431        editor._subscriptions.extend(project_subscriptions);
 2432
 2433        editor._subscriptions.push(cx.subscribe_in(
 2434            &cx.entity(),
 2435            window,
 2436            |editor, _, e: &EditorEvent, window, cx| match e {
 2437                EditorEvent::ScrollPositionChanged { local, .. } => {
 2438                    if *local {
 2439                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2440                        editor.inline_blame_popover.take();
 2441                        let new_anchor = editor.scroll_manager.anchor();
 2442                        let snapshot = editor.snapshot(window, cx);
 2443                        editor.update_restoration_data(cx, move |data| {
 2444                            data.scroll_position = (
 2445                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2446                                new_anchor.offset,
 2447                            );
 2448                        });
 2449
 2450                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2451                            cx.background_executor()
 2452                                .timer(Duration::from_millis(50))
 2453                                .await;
 2454                            editor
 2455                                .update_in(cx, |editor, window, cx| {
 2456                                    editor.register_visible_buffers(cx);
 2457                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2458                                    editor.refresh_inlay_hints(
 2459                                        InlayHintRefreshReason::NewLinesShown,
 2460                                        cx,
 2461                                    );
 2462                                    editor.colorize_brackets(false, cx);
 2463                                })
 2464                                .ok();
 2465                        });
 2466                    }
 2467                }
 2468                EditorEvent::Edited { .. } => {
 2469                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2470                        .map(|vim_mode| vim_mode.0)
 2471                        .unwrap_or(false);
 2472                    if !vim_mode {
 2473                        let display_map = editor.display_snapshot(cx);
 2474                        let selections = editor.selections.all_adjusted_display(&display_map);
 2475                        let pop_state = editor
 2476                            .change_list
 2477                            .last()
 2478                            .map(|previous| {
 2479                                previous.len() == selections.len()
 2480                                    && previous.iter().enumerate().all(|(ix, p)| {
 2481                                        p.to_display_point(&display_map).row()
 2482                                            == selections[ix].head().row()
 2483                                    })
 2484                            })
 2485                            .unwrap_or(false);
 2486                        let new_positions = selections
 2487                            .into_iter()
 2488                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2489                            .collect();
 2490                        editor
 2491                            .change_list
 2492                            .push_to_change_list(pop_state, new_positions);
 2493                    }
 2494                }
 2495                _ => (),
 2496            },
 2497        ));
 2498
 2499        if let Some(dap_store) = editor
 2500            .project
 2501            .as_ref()
 2502            .map(|project| project.read(cx).dap_store())
 2503        {
 2504            let weak_editor = cx.weak_entity();
 2505
 2506            editor
 2507                ._subscriptions
 2508                .push(
 2509                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2510                        let session_entity = cx.entity();
 2511                        weak_editor
 2512                            .update(cx, |editor, cx| {
 2513                                editor._subscriptions.push(
 2514                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2515                                );
 2516                            })
 2517                            .ok();
 2518                    }),
 2519                );
 2520
 2521            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2522                editor
 2523                    ._subscriptions
 2524                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2525            }
 2526        }
 2527
 2528        // skip adding the initial selection to selection history
 2529        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2530        editor.end_selection(window, cx);
 2531        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2532
 2533        editor.scroll_manager.show_scrollbars(window, cx);
 2534        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2535
 2536        if full_mode {
 2537            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2538            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2539
 2540            if editor.git_blame_inline_enabled {
 2541                editor.start_git_blame_inline(false, window, cx);
 2542            }
 2543
 2544            editor.go_to_active_debug_line(window, cx);
 2545
 2546            editor.minimap =
 2547                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2548            editor.colors = Some(LspColorData::new(cx));
 2549            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2550
 2551            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2552                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2553            }
 2554            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2555        }
 2556
 2557        editor
 2558    }
 2559
 2560    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2561        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2562    }
 2563
 2564    pub fn deploy_mouse_context_menu(
 2565        &mut self,
 2566        position: gpui::Point<Pixels>,
 2567        context_menu: Entity<ContextMenu>,
 2568        window: &mut Window,
 2569        cx: &mut Context<Self>,
 2570    ) {
 2571        self.mouse_context_menu = Some(MouseContextMenu::new(
 2572            self,
 2573            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2574            context_menu,
 2575            window,
 2576            cx,
 2577        ));
 2578    }
 2579
 2580    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2581        self.mouse_context_menu
 2582            .as_ref()
 2583            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2584    }
 2585
 2586    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2587        if self
 2588            .selections
 2589            .pending_anchor()
 2590            .is_some_and(|pending_selection| {
 2591                let snapshot = self.buffer().read(cx).snapshot(cx);
 2592                pending_selection.range().includes(range, &snapshot)
 2593            })
 2594        {
 2595            return true;
 2596        }
 2597
 2598        self.selections
 2599            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2600            .into_iter()
 2601            .any(|selection| {
 2602                // This is needed to cover a corner case, if we just check for an existing
 2603                // selection in the fold range, having a cursor at the start of the fold
 2604                // marks it as selected. Non-empty selections don't cause this.
 2605                let length = selection.end - selection.start;
 2606                length > 0
 2607            })
 2608    }
 2609
 2610    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2611        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2612    }
 2613
 2614    fn key_context_internal(
 2615        &self,
 2616        has_active_edit_prediction: bool,
 2617        window: &mut Window,
 2618        cx: &mut App,
 2619    ) -> KeyContext {
 2620        let mut key_context = KeyContext::new_with_defaults();
 2621        key_context.add("Editor");
 2622        let mode = match self.mode {
 2623            EditorMode::SingleLine => "single_line",
 2624            EditorMode::AutoHeight { .. } => "auto_height",
 2625            EditorMode::Minimap { .. } => "minimap",
 2626            EditorMode::Full { .. } => "full",
 2627        };
 2628
 2629        if EditorSettings::jupyter_enabled(cx) {
 2630            key_context.add("jupyter");
 2631        }
 2632
 2633        key_context.set("mode", mode);
 2634        if self.pending_rename.is_some() {
 2635            key_context.add("renaming");
 2636        }
 2637
 2638        if let Some(snippet_stack) = self.snippet_stack.last() {
 2639            key_context.add("in_snippet");
 2640
 2641            if snippet_stack.active_index > 0 {
 2642                key_context.add("has_previous_tabstop");
 2643            }
 2644
 2645            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2646                key_context.add("has_next_tabstop");
 2647            }
 2648        }
 2649
 2650        match self.context_menu.borrow().as_ref() {
 2651            Some(CodeContextMenu::Completions(menu)) => {
 2652                if menu.visible() {
 2653                    key_context.add("menu");
 2654                    key_context.add("showing_completions");
 2655                }
 2656            }
 2657            Some(CodeContextMenu::CodeActions(menu)) => {
 2658                if menu.visible() {
 2659                    key_context.add("menu");
 2660                    key_context.add("showing_code_actions")
 2661                }
 2662            }
 2663            None => {}
 2664        }
 2665
 2666        if self.signature_help_state.has_multiple_signatures() {
 2667            key_context.add("showing_signature_help");
 2668        }
 2669
 2670        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2671        if !self.focus_handle(cx).contains_focused(window, cx)
 2672            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2673        {
 2674            for addon in self.addons.values() {
 2675                addon.extend_key_context(&mut key_context, cx)
 2676            }
 2677        }
 2678
 2679        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2680            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2681                Some(
 2682                    file.full_path(cx)
 2683                        .extension()?
 2684                        .to_string_lossy()
 2685                        .into_owned(),
 2686                )
 2687            }) {
 2688                key_context.set("extension", extension);
 2689            }
 2690        } else {
 2691            key_context.add("multibuffer");
 2692        }
 2693
 2694        if has_active_edit_prediction {
 2695            if self.edit_prediction_in_conflict() {
 2696                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2697            } else {
 2698                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2699                key_context.add("copilot_suggestion");
 2700            }
 2701        }
 2702
 2703        if self.selection_mark_mode {
 2704            key_context.add("selection_mode");
 2705        }
 2706
 2707        let disjoint = self.selections.disjoint_anchors();
 2708        let snapshot = self.snapshot(window, cx);
 2709        let snapshot = snapshot.buffer_snapshot();
 2710        if self.mode == EditorMode::SingleLine
 2711            && let [selection] = disjoint
 2712            && selection.start == selection.end
 2713            && selection.end.to_offset(snapshot) == snapshot.len()
 2714        {
 2715            key_context.add("end_of_input");
 2716        }
 2717
 2718        if self.has_any_expanded_diff_hunks(cx) {
 2719            key_context.add("diffs_expanded");
 2720        }
 2721
 2722        key_context
 2723    }
 2724
 2725    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2726        self.last_bounds.as_ref()
 2727    }
 2728
 2729    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2730        if self.mouse_cursor_hidden {
 2731            self.mouse_cursor_hidden = false;
 2732            cx.notify();
 2733        }
 2734    }
 2735
 2736    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2737        let hide_mouse_cursor = match origin {
 2738            HideMouseCursorOrigin::TypingAction => {
 2739                matches!(
 2740                    self.hide_mouse_mode,
 2741                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2742                )
 2743            }
 2744            HideMouseCursorOrigin::MovementAction => {
 2745                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2746            }
 2747        };
 2748        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2749            self.mouse_cursor_hidden = hide_mouse_cursor;
 2750            cx.notify();
 2751        }
 2752    }
 2753
 2754    pub fn edit_prediction_in_conflict(&self) -> bool {
 2755        if !self.show_edit_predictions_in_menu() {
 2756            return false;
 2757        }
 2758
 2759        let showing_completions = self
 2760            .context_menu
 2761            .borrow()
 2762            .as_ref()
 2763            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2764
 2765        showing_completions
 2766            || self.edit_prediction_requires_modifier()
 2767            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2768            // bindings to insert tab characters.
 2769            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2770    }
 2771
 2772    pub fn accept_edit_prediction_keybind(
 2773        &self,
 2774        accept_partial: bool,
 2775        window: &mut Window,
 2776        cx: &mut App,
 2777    ) -> AcceptEditPredictionBinding {
 2778        let key_context = self.key_context_internal(true, window, cx);
 2779        let in_conflict = self.edit_prediction_in_conflict();
 2780
 2781        let bindings = if accept_partial {
 2782            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2783        } else {
 2784            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2785        };
 2786
 2787        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2788        // just the first one.
 2789        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2790            !in_conflict
 2791                || binding
 2792                    .keystrokes()
 2793                    .first()
 2794                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2795        }))
 2796    }
 2797
 2798    pub fn new_file(
 2799        workspace: &mut Workspace,
 2800        _: &workspace::NewFile,
 2801        window: &mut Window,
 2802        cx: &mut Context<Workspace>,
 2803    ) {
 2804        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2805            "Failed to create buffer",
 2806            window,
 2807            cx,
 2808            |e, _, _| match e.error_code() {
 2809                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2810                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2811                e.error_tag("required").unwrap_or("the latest version")
 2812            )),
 2813                _ => None,
 2814            },
 2815        );
 2816    }
 2817
 2818    pub fn new_in_workspace(
 2819        workspace: &mut Workspace,
 2820        window: &mut Window,
 2821        cx: &mut Context<Workspace>,
 2822    ) -> Task<Result<Entity<Editor>>> {
 2823        let project = workspace.project().clone();
 2824        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2825
 2826        cx.spawn_in(window, async move |workspace, cx| {
 2827            let buffer = create.await?;
 2828            workspace.update_in(cx, |workspace, window, cx| {
 2829                let editor =
 2830                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2831                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2832                editor
 2833            })
 2834        })
 2835    }
 2836
 2837    fn new_file_vertical(
 2838        workspace: &mut Workspace,
 2839        _: &workspace::NewFileSplitVertical,
 2840        window: &mut Window,
 2841        cx: &mut Context<Workspace>,
 2842    ) {
 2843        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2844    }
 2845
 2846    fn new_file_horizontal(
 2847        workspace: &mut Workspace,
 2848        _: &workspace::NewFileSplitHorizontal,
 2849        window: &mut Window,
 2850        cx: &mut Context<Workspace>,
 2851    ) {
 2852        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2853    }
 2854
 2855    fn new_file_split(
 2856        workspace: &mut Workspace,
 2857        action: &workspace::NewFileSplit,
 2858        window: &mut Window,
 2859        cx: &mut Context<Workspace>,
 2860    ) {
 2861        Self::new_file_in_direction(workspace, action.0, window, cx)
 2862    }
 2863
 2864    fn new_file_in_direction(
 2865        workspace: &mut Workspace,
 2866        direction: SplitDirection,
 2867        window: &mut Window,
 2868        cx: &mut Context<Workspace>,
 2869    ) {
 2870        let project = workspace.project().clone();
 2871        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2872
 2873        cx.spawn_in(window, async move |workspace, cx| {
 2874            let buffer = create.await?;
 2875            workspace.update_in(cx, move |workspace, window, cx| {
 2876                workspace.split_item(
 2877                    direction,
 2878                    Box::new(
 2879                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2880                    ),
 2881                    window,
 2882                    cx,
 2883                )
 2884            })?;
 2885            anyhow::Ok(())
 2886        })
 2887        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2888            match e.error_code() {
 2889                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2890                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2891                e.error_tag("required").unwrap_or("the latest version")
 2892            )),
 2893                _ => None,
 2894            }
 2895        });
 2896    }
 2897
 2898    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2899        self.leader_id
 2900    }
 2901
 2902    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2903        &self.buffer
 2904    }
 2905
 2906    pub fn project(&self) -> Option<&Entity<Project>> {
 2907        self.project.as_ref()
 2908    }
 2909
 2910    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2911        self.workspace.as_ref()?.0.upgrade()
 2912    }
 2913
 2914    /// Returns the workspace serialization ID if this editor should be serialized.
 2915    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2916        self.workspace
 2917            .as_ref()
 2918            .filter(|_| self.should_serialize_buffer())
 2919            .and_then(|workspace| workspace.1)
 2920    }
 2921
 2922    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2923        self.buffer().read(cx).title(cx)
 2924    }
 2925
 2926    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2927        let git_blame_gutter_max_author_length = self
 2928            .render_git_blame_gutter(cx)
 2929            .then(|| {
 2930                if let Some(blame) = self.blame.as_ref() {
 2931                    let max_author_length =
 2932                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2933                    Some(max_author_length)
 2934                } else {
 2935                    None
 2936                }
 2937            })
 2938            .flatten();
 2939
 2940        EditorSnapshot {
 2941            mode: self.mode.clone(),
 2942            show_gutter: self.show_gutter,
 2943            offset_content: self.offset_content,
 2944            show_line_numbers: self.show_line_numbers,
 2945            show_git_diff_gutter: self.show_git_diff_gutter,
 2946            show_code_actions: self.show_code_actions,
 2947            show_runnables: self.show_runnables,
 2948            show_breakpoints: self.show_breakpoints,
 2949            git_blame_gutter_max_author_length,
 2950            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2951            placeholder_display_snapshot: self
 2952                .placeholder_display_map
 2953                .as_ref()
 2954                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2955            scroll_anchor: self.scroll_manager.anchor(),
 2956            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2957            is_focused: self.focus_handle.is_focused(window),
 2958            current_line_highlight: self
 2959                .current_line_highlight
 2960                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2961            gutter_hovered: self.gutter_hovered,
 2962        }
 2963    }
 2964
 2965    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2966        self.buffer.read(cx).language_at(point, cx)
 2967    }
 2968
 2969    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2970        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2971    }
 2972
 2973    pub fn active_excerpt(
 2974        &self,
 2975        cx: &App,
 2976    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2977        self.buffer
 2978            .read(cx)
 2979            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2980    }
 2981
 2982    pub fn mode(&self) -> &EditorMode {
 2983        &self.mode
 2984    }
 2985
 2986    pub fn set_mode(&mut self, mode: EditorMode) {
 2987        self.mode = mode;
 2988    }
 2989
 2990    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2991        self.collaboration_hub.as_deref()
 2992    }
 2993
 2994    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2995        self.collaboration_hub = Some(hub);
 2996    }
 2997
 2998    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2999        self.in_project_search = in_project_search;
 3000    }
 3001
 3002    pub fn set_custom_context_menu(
 3003        &mut self,
 3004        f: impl 'static
 3005        + Fn(
 3006            &mut Self,
 3007            DisplayPoint,
 3008            &mut Window,
 3009            &mut Context<Self>,
 3010        ) -> Option<Entity<ui::ContextMenu>>,
 3011    ) {
 3012        self.custom_context_menu = Some(Box::new(f))
 3013    }
 3014
 3015    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3016        self.completion_provider = provider;
 3017    }
 3018
 3019    #[cfg(any(test, feature = "test-support"))]
 3020    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3021        self.completion_provider.clone()
 3022    }
 3023
 3024    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3025        self.semantics_provider.clone()
 3026    }
 3027
 3028    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3029        self.semantics_provider = provider;
 3030    }
 3031
 3032    pub fn set_edit_prediction_provider<T>(
 3033        &mut self,
 3034        provider: Option<Entity<T>>,
 3035        window: &mut Window,
 3036        cx: &mut Context<Self>,
 3037    ) where
 3038        T: EditPredictionDelegate,
 3039    {
 3040        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3041            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3042                if this.focus_handle.is_focused(window) {
 3043                    this.update_visible_edit_prediction(window, cx);
 3044                }
 3045            }),
 3046            provider: Arc::new(provider),
 3047        });
 3048        self.update_edit_prediction_settings(cx);
 3049        self.refresh_edit_prediction(false, false, window, cx);
 3050    }
 3051
 3052    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3053        self.placeholder_display_map
 3054            .as_ref()
 3055            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3056    }
 3057
 3058    pub fn set_placeholder_text(
 3059        &mut self,
 3060        placeholder_text: &str,
 3061        window: &mut Window,
 3062        cx: &mut Context<Self>,
 3063    ) {
 3064        let multibuffer = cx
 3065            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3066
 3067        let style = window.text_style();
 3068
 3069        self.placeholder_display_map = Some(cx.new(|cx| {
 3070            DisplayMap::new(
 3071                multibuffer,
 3072                style.font(),
 3073                style.font_size.to_pixels(window.rem_size()),
 3074                None,
 3075                FILE_HEADER_HEIGHT,
 3076                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3077                Default::default(),
 3078                DiagnosticSeverity::Off,
 3079                cx,
 3080            )
 3081        }));
 3082        cx.notify();
 3083    }
 3084
 3085    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3086        self.cursor_shape = cursor_shape;
 3087
 3088        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3089        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3090
 3091        cx.notify();
 3092    }
 3093
 3094    pub fn cursor_shape(&self) -> CursorShape {
 3095        self.cursor_shape
 3096    }
 3097
 3098    pub fn set_current_line_highlight(
 3099        &mut self,
 3100        current_line_highlight: Option<CurrentLineHighlight>,
 3101    ) {
 3102        self.current_line_highlight = current_line_highlight;
 3103    }
 3104
 3105    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3106        self.collapse_matches = collapse_matches;
 3107    }
 3108
 3109    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3110        if self.collapse_matches {
 3111            return range.start..range.start;
 3112        }
 3113        range.clone()
 3114    }
 3115
 3116    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3117        self.display_map.read(cx).clip_at_line_ends
 3118    }
 3119
 3120    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3121        if self.display_map.read(cx).clip_at_line_ends != clip {
 3122            self.display_map
 3123                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3124        }
 3125    }
 3126
 3127    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3128        self.input_enabled = input_enabled;
 3129    }
 3130
 3131    pub fn set_edit_predictions_hidden_for_vim_mode(
 3132        &mut self,
 3133        hidden: bool,
 3134        window: &mut Window,
 3135        cx: &mut Context<Self>,
 3136    ) {
 3137        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3138            self.edit_predictions_hidden_for_vim_mode = hidden;
 3139            if hidden {
 3140                self.update_visible_edit_prediction(window, cx);
 3141            } else {
 3142                self.refresh_edit_prediction(true, false, window, cx);
 3143            }
 3144        }
 3145    }
 3146
 3147    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3148        self.menu_edit_predictions_policy = value;
 3149    }
 3150
 3151    pub fn set_autoindent(&mut self, autoindent: bool) {
 3152        if autoindent {
 3153            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3154        } else {
 3155            self.autoindent_mode = None;
 3156        }
 3157    }
 3158
 3159    pub fn read_only(&self, cx: &App) -> bool {
 3160        self.read_only || self.buffer.read(cx).read_only()
 3161    }
 3162
 3163    pub fn set_read_only(&mut self, read_only: bool) {
 3164        self.read_only = read_only;
 3165    }
 3166
 3167    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3168        self.use_autoclose = autoclose;
 3169    }
 3170
 3171    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3172        self.use_auto_surround = auto_surround;
 3173    }
 3174
 3175    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3176        self.auto_replace_emoji_shortcode = auto_replace;
 3177    }
 3178
 3179    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3180        self.buffer_serialization = should_serialize.then(|| {
 3181            BufferSerialization::new(
 3182                ProjectSettings::get_global(cx)
 3183                    .session
 3184                    .restore_unsaved_buffers,
 3185            )
 3186        })
 3187    }
 3188
 3189    fn should_serialize_buffer(&self) -> bool {
 3190        self.buffer_serialization.is_some()
 3191    }
 3192
 3193    pub fn toggle_edit_predictions(
 3194        &mut self,
 3195        _: &ToggleEditPrediction,
 3196        window: &mut Window,
 3197        cx: &mut Context<Self>,
 3198    ) {
 3199        if self.show_edit_predictions_override.is_some() {
 3200            self.set_show_edit_predictions(None, window, cx);
 3201        } else {
 3202            let show_edit_predictions = !self.edit_predictions_enabled();
 3203            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3204        }
 3205    }
 3206
 3207    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3208        self.show_completions_on_input_override = show_completions_on_input;
 3209    }
 3210
 3211    pub fn set_show_edit_predictions(
 3212        &mut self,
 3213        show_edit_predictions: Option<bool>,
 3214        window: &mut Window,
 3215        cx: &mut Context<Self>,
 3216    ) {
 3217        self.show_edit_predictions_override = show_edit_predictions;
 3218        self.update_edit_prediction_settings(cx);
 3219
 3220        if let Some(false) = show_edit_predictions {
 3221            self.discard_edit_prediction(false, cx);
 3222        } else {
 3223            self.refresh_edit_prediction(false, true, window, cx);
 3224        }
 3225    }
 3226
 3227    fn edit_predictions_disabled_in_scope(
 3228        &self,
 3229        buffer: &Entity<Buffer>,
 3230        buffer_position: language::Anchor,
 3231        cx: &App,
 3232    ) -> bool {
 3233        let snapshot = buffer.read(cx).snapshot();
 3234        let settings = snapshot.settings_at(buffer_position, cx);
 3235
 3236        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3237            return false;
 3238        };
 3239
 3240        scope.override_name().is_some_and(|scope_name| {
 3241            settings
 3242                .edit_predictions_disabled_in
 3243                .iter()
 3244                .any(|s| s == scope_name)
 3245        })
 3246    }
 3247
 3248    pub fn set_use_modal_editing(&mut self, to: bool) {
 3249        self.use_modal_editing = to;
 3250    }
 3251
 3252    pub fn use_modal_editing(&self) -> bool {
 3253        self.use_modal_editing
 3254    }
 3255
 3256    fn selections_did_change(
 3257        &mut self,
 3258        local: bool,
 3259        old_cursor_position: &Anchor,
 3260        effects: SelectionEffects,
 3261        window: &mut Window,
 3262        cx: &mut Context<Self>,
 3263    ) {
 3264        window.invalidate_character_coordinates();
 3265
 3266        // Copy selections to primary selection buffer
 3267        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3268        if local {
 3269            let selections = self
 3270                .selections
 3271                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3272            let buffer_handle = self.buffer.read(cx).read(cx);
 3273
 3274            let mut text = String::new();
 3275            for (index, selection) in selections.iter().enumerate() {
 3276                let text_for_selection = buffer_handle
 3277                    .text_for_range(selection.start..selection.end)
 3278                    .collect::<String>();
 3279
 3280                text.push_str(&text_for_selection);
 3281                if index != selections.len() - 1 {
 3282                    text.push('\n');
 3283                }
 3284            }
 3285
 3286            if !text.is_empty() {
 3287                cx.write_to_primary(ClipboardItem::new_string(text));
 3288            }
 3289        }
 3290
 3291        let selection_anchors = self.selections.disjoint_anchors_arc();
 3292
 3293        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3294            self.buffer.update(cx, |buffer, cx| {
 3295                buffer.set_active_selections(
 3296                    &selection_anchors,
 3297                    self.selections.line_mode(),
 3298                    self.cursor_shape,
 3299                    cx,
 3300                )
 3301            });
 3302        }
 3303        let display_map = self
 3304            .display_map
 3305            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3306        let buffer = display_map.buffer_snapshot();
 3307        if self.selections.count() == 1 {
 3308            self.add_selections_state = None;
 3309        }
 3310        self.select_next_state = None;
 3311        self.select_prev_state = None;
 3312        self.select_syntax_node_history.try_clear();
 3313        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3314        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3315        self.take_rename(false, window, cx);
 3316
 3317        let newest_selection = self.selections.newest_anchor();
 3318        let new_cursor_position = newest_selection.head();
 3319        let selection_start = newest_selection.start;
 3320
 3321        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3322            self.push_to_nav_history(
 3323                *old_cursor_position,
 3324                Some(new_cursor_position.to_point(buffer)),
 3325                false,
 3326                effects.nav_history == Some(true),
 3327                cx,
 3328            );
 3329        }
 3330
 3331        if local {
 3332            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3333                self.register_buffer(buffer_id, cx);
 3334            }
 3335
 3336            let mut context_menu = self.context_menu.borrow_mut();
 3337            let completion_menu = match context_menu.as_ref() {
 3338                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3339                Some(CodeContextMenu::CodeActions(_)) => {
 3340                    *context_menu = None;
 3341                    None
 3342                }
 3343                None => None,
 3344            };
 3345            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3346            drop(context_menu);
 3347
 3348            if effects.completions
 3349                && let Some(completion_position) = completion_position
 3350            {
 3351                let start_offset = selection_start.to_offset(buffer);
 3352                let position_matches = start_offset == completion_position.to_offset(buffer);
 3353                let continue_showing = if position_matches {
 3354                    if self.snippet_stack.is_empty() {
 3355                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3356                            == Some(CharKind::Word)
 3357                    } else {
 3358                        // Snippet choices can be shown even when the cursor is in whitespace.
 3359                        // Dismissing the menu with actions like backspace is handled by
 3360                        // invalidation regions.
 3361                        true
 3362                    }
 3363                } else {
 3364                    false
 3365                };
 3366
 3367                if continue_showing {
 3368                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3369                } else {
 3370                    self.hide_context_menu(window, cx);
 3371                }
 3372            }
 3373
 3374            hide_hover(self, cx);
 3375
 3376            if old_cursor_position.to_display_point(&display_map).row()
 3377                != new_cursor_position.to_display_point(&display_map).row()
 3378            {
 3379                self.available_code_actions.take();
 3380            }
 3381            self.refresh_code_actions(window, cx);
 3382            self.refresh_document_highlights(cx);
 3383            refresh_linked_ranges(self, window, cx);
 3384
 3385            self.refresh_selected_text_highlights(false, window, cx);
 3386            self.refresh_matching_bracket_highlights(window, cx);
 3387            self.update_visible_edit_prediction(window, cx);
 3388            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3389            self.inline_blame_popover.take();
 3390            if self.git_blame_inline_enabled {
 3391                self.start_inline_blame_timer(window, cx);
 3392            }
 3393        }
 3394
 3395        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3396        cx.emit(EditorEvent::SelectionsChanged { local });
 3397
 3398        let selections = &self.selections.disjoint_anchors_arc();
 3399        if selections.len() == 1 {
 3400            cx.emit(SearchEvent::ActiveMatchChanged)
 3401        }
 3402        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3403            let inmemory_selections = selections
 3404                .iter()
 3405                .map(|s| {
 3406                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3407                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3408                })
 3409                .collect();
 3410            self.update_restoration_data(cx, |data| {
 3411                data.selections = inmemory_selections;
 3412            });
 3413
 3414            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3415                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3416            {
 3417                let snapshot = self.buffer().read(cx).snapshot(cx);
 3418                let selections = selections.clone();
 3419                let background_executor = cx.background_executor().clone();
 3420                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3421                self.serialize_selections = cx.background_spawn(async move {
 3422                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3423                    let db_selections = selections
 3424                        .iter()
 3425                        .map(|selection| {
 3426                            (
 3427                                selection.start.to_offset(&snapshot).0,
 3428                                selection.end.to_offset(&snapshot).0,
 3429                            )
 3430                        })
 3431                        .collect();
 3432
 3433                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3434                        .await
 3435                        .with_context(|| {
 3436                            format!(
 3437                                "persisting editor selections for editor {editor_id}, \
 3438                                workspace {workspace_id:?}"
 3439                            )
 3440                        })
 3441                        .log_err();
 3442                });
 3443            }
 3444        }
 3445
 3446        cx.notify();
 3447    }
 3448
 3449    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3450        use text::ToOffset as _;
 3451        use text::ToPoint as _;
 3452
 3453        if self.mode.is_minimap()
 3454            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3455        {
 3456            return;
 3457        }
 3458
 3459        if !self.buffer().read(cx).is_singleton() {
 3460            return;
 3461        }
 3462
 3463        let display_snapshot = self
 3464            .display_map
 3465            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3466        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3467            return;
 3468        };
 3469        let inmemory_folds = display_snapshot
 3470            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3471            .map(|fold| {
 3472                fold.range.start.text_anchor.to_point(&snapshot)
 3473                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3474            })
 3475            .collect();
 3476        self.update_restoration_data(cx, |data| {
 3477            data.folds = inmemory_folds;
 3478        });
 3479
 3480        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3481            return;
 3482        };
 3483        let background_executor = cx.background_executor().clone();
 3484        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3485        let db_folds = display_snapshot
 3486            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3487            .map(|fold| {
 3488                (
 3489                    fold.range.start.text_anchor.to_offset(&snapshot),
 3490                    fold.range.end.text_anchor.to_offset(&snapshot),
 3491                )
 3492            })
 3493            .collect();
 3494        self.serialize_folds = cx.background_spawn(async move {
 3495            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3496            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3497                .await
 3498                .with_context(|| {
 3499                    format!(
 3500                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3501                    )
 3502                })
 3503                .log_err();
 3504        });
 3505    }
 3506
 3507    pub fn sync_selections(
 3508        &mut self,
 3509        other: Entity<Editor>,
 3510        cx: &mut Context<Self>,
 3511    ) -> gpui::Subscription {
 3512        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3513        if !other_selections.is_empty() {
 3514            self.selections
 3515                .change_with(&self.display_snapshot(cx), |selections| {
 3516                    selections.select_anchors(other_selections);
 3517                });
 3518        }
 3519
 3520        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3521            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3522                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3523                if other_selections.is_empty() {
 3524                    return;
 3525                }
 3526                let snapshot = this.display_snapshot(cx);
 3527                this.selections.change_with(&snapshot, |selections| {
 3528                    selections.select_anchors(other_selections);
 3529                });
 3530            }
 3531        });
 3532
 3533        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3534            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3535                let these_selections = this.selections.disjoint_anchors().to_vec();
 3536                if these_selections.is_empty() {
 3537                    return;
 3538                }
 3539                other.update(cx, |other_editor, cx| {
 3540                    let snapshot = other_editor.display_snapshot(cx);
 3541                    other_editor
 3542                        .selections
 3543                        .change_with(&snapshot, |selections| {
 3544                            selections.select_anchors(these_selections);
 3545                        })
 3546                });
 3547            }
 3548        });
 3549
 3550        Subscription::join(other_subscription, this_subscription)
 3551    }
 3552
 3553    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3554        if self.buffer().read(cx).is_singleton() {
 3555            return;
 3556        }
 3557        let snapshot = self.buffer.read(cx).snapshot(cx);
 3558        let buffer_ids: HashSet<BufferId> = self
 3559            .selections
 3560            .disjoint_anchor_ranges()
 3561            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3562            .collect();
 3563        for buffer_id in buffer_ids {
 3564            self.unfold_buffer(buffer_id, cx);
 3565        }
 3566    }
 3567
 3568    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3569    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3570    /// effects of selection change occur at the end of the transaction.
 3571    pub fn change_selections<R>(
 3572        &mut self,
 3573        effects: SelectionEffects,
 3574        window: &mut Window,
 3575        cx: &mut Context<Self>,
 3576        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3577    ) -> R {
 3578        let snapshot = self.display_snapshot(cx);
 3579        if let Some(state) = &mut self.deferred_selection_effects_state {
 3580            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3581            state.effects.completions = effects.completions;
 3582            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3583            let (changed, result) = self.selections.change_with(&snapshot, change);
 3584            state.changed |= changed;
 3585            return result;
 3586        }
 3587        let mut state = DeferredSelectionEffectsState {
 3588            changed: false,
 3589            effects,
 3590            old_cursor_position: self.selections.newest_anchor().head(),
 3591            history_entry: SelectionHistoryEntry {
 3592                selections: self.selections.disjoint_anchors_arc(),
 3593                select_next_state: self.select_next_state.clone(),
 3594                select_prev_state: self.select_prev_state.clone(),
 3595                add_selections_state: self.add_selections_state.clone(),
 3596            },
 3597        };
 3598        let (changed, result) = self.selections.change_with(&snapshot, change);
 3599        state.changed = state.changed || changed;
 3600        if self.defer_selection_effects {
 3601            self.deferred_selection_effects_state = Some(state);
 3602        } else {
 3603            self.apply_selection_effects(state, window, cx);
 3604        }
 3605        result
 3606    }
 3607
 3608    /// Defers the effects of selection change, so that the effects of multiple calls to
 3609    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3610    /// to selection history and the state of popovers based on selection position aren't
 3611    /// erroneously updated.
 3612    pub fn with_selection_effects_deferred<R>(
 3613        &mut self,
 3614        window: &mut Window,
 3615        cx: &mut Context<Self>,
 3616        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3617    ) -> R {
 3618        let already_deferred = self.defer_selection_effects;
 3619        self.defer_selection_effects = true;
 3620        let result = update(self, window, cx);
 3621        if !already_deferred {
 3622            self.defer_selection_effects = false;
 3623            if let Some(state) = self.deferred_selection_effects_state.take() {
 3624                self.apply_selection_effects(state, window, cx);
 3625            }
 3626        }
 3627        result
 3628    }
 3629
 3630    fn apply_selection_effects(
 3631        &mut self,
 3632        state: DeferredSelectionEffectsState,
 3633        window: &mut Window,
 3634        cx: &mut Context<Self>,
 3635    ) {
 3636        if state.changed {
 3637            self.selection_history.push(state.history_entry);
 3638
 3639            if let Some(autoscroll) = state.effects.scroll {
 3640                self.request_autoscroll(autoscroll, cx);
 3641            }
 3642
 3643            let old_cursor_position = &state.old_cursor_position;
 3644
 3645            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3646
 3647            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3648                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3649            }
 3650        }
 3651    }
 3652
 3653    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3654    where
 3655        I: IntoIterator<Item = (Range<S>, T)>,
 3656        S: ToOffset,
 3657        T: Into<Arc<str>>,
 3658    {
 3659        if self.read_only(cx) {
 3660            return;
 3661        }
 3662
 3663        self.buffer
 3664            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3665    }
 3666
 3667    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3668    where
 3669        I: IntoIterator<Item = (Range<S>, T)>,
 3670        S: ToOffset,
 3671        T: Into<Arc<str>>,
 3672    {
 3673        if self.read_only(cx) {
 3674            return;
 3675        }
 3676
 3677        self.buffer.update(cx, |buffer, cx| {
 3678            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3679        });
 3680    }
 3681
 3682    pub fn edit_with_block_indent<I, S, T>(
 3683        &mut self,
 3684        edits: I,
 3685        original_indent_columns: Vec<Option<u32>>,
 3686        cx: &mut Context<Self>,
 3687    ) where
 3688        I: IntoIterator<Item = (Range<S>, T)>,
 3689        S: ToOffset,
 3690        T: Into<Arc<str>>,
 3691    {
 3692        if self.read_only(cx) {
 3693            return;
 3694        }
 3695
 3696        self.buffer.update(cx, |buffer, cx| {
 3697            buffer.edit(
 3698                edits,
 3699                Some(AutoindentMode::Block {
 3700                    original_indent_columns,
 3701                }),
 3702                cx,
 3703            )
 3704        });
 3705    }
 3706
 3707    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3708        self.hide_context_menu(window, cx);
 3709
 3710        match phase {
 3711            SelectPhase::Begin {
 3712                position,
 3713                add,
 3714                click_count,
 3715            } => self.begin_selection(position, add, click_count, window, cx),
 3716            SelectPhase::BeginColumnar {
 3717                position,
 3718                goal_column,
 3719                reset,
 3720                mode,
 3721            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3722            SelectPhase::Extend {
 3723                position,
 3724                click_count,
 3725            } => self.extend_selection(position, click_count, window, cx),
 3726            SelectPhase::Update {
 3727                position,
 3728                goal_column,
 3729                scroll_delta,
 3730            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3731            SelectPhase::End => self.end_selection(window, cx),
 3732        }
 3733    }
 3734
 3735    fn extend_selection(
 3736        &mut self,
 3737        position: DisplayPoint,
 3738        click_count: usize,
 3739        window: &mut Window,
 3740        cx: &mut Context<Self>,
 3741    ) {
 3742        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3743        let tail = self
 3744            .selections
 3745            .newest::<MultiBufferOffset>(&display_map)
 3746            .tail();
 3747        let click_count = click_count.max(match self.selections.select_mode() {
 3748            SelectMode::Character => 1,
 3749            SelectMode::Word(_) => 2,
 3750            SelectMode::Line(_) => 3,
 3751            SelectMode::All => 4,
 3752        });
 3753        self.begin_selection(position, false, click_count, window, cx);
 3754
 3755        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3756
 3757        let current_selection = match self.selections.select_mode() {
 3758            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3759            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3760        };
 3761
 3762        let mut pending_selection = self
 3763            .selections
 3764            .pending_anchor()
 3765            .cloned()
 3766            .expect("extend_selection not called with pending selection");
 3767
 3768        if pending_selection
 3769            .start
 3770            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3771            == Ordering::Greater
 3772        {
 3773            pending_selection.start = current_selection.start;
 3774        }
 3775        if pending_selection
 3776            .end
 3777            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3778            == Ordering::Less
 3779        {
 3780            pending_selection.end = current_selection.end;
 3781            pending_selection.reversed = true;
 3782        }
 3783
 3784        let mut pending_mode = self.selections.pending_mode().unwrap();
 3785        match &mut pending_mode {
 3786            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3787            _ => {}
 3788        }
 3789
 3790        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3791            SelectionEffects::scroll(Autoscroll::fit())
 3792        } else {
 3793            SelectionEffects::no_scroll()
 3794        };
 3795
 3796        self.change_selections(effects, window, cx, |s| {
 3797            s.set_pending(pending_selection.clone(), pending_mode);
 3798            s.set_is_extending(true);
 3799        });
 3800    }
 3801
 3802    fn begin_selection(
 3803        &mut self,
 3804        position: DisplayPoint,
 3805        add: bool,
 3806        click_count: usize,
 3807        window: &mut Window,
 3808        cx: &mut Context<Self>,
 3809    ) {
 3810        if !self.focus_handle.is_focused(window) {
 3811            self.last_focused_descendant = None;
 3812            window.focus(&self.focus_handle);
 3813        }
 3814
 3815        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3816        let buffer = display_map.buffer_snapshot();
 3817        let position = display_map.clip_point(position, Bias::Left);
 3818
 3819        let start;
 3820        let end;
 3821        let mode;
 3822        let mut auto_scroll;
 3823        match click_count {
 3824            1 => {
 3825                start = buffer.anchor_before(position.to_point(&display_map));
 3826                end = start;
 3827                mode = SelectMode::Character;
 3828                auto_scroll = true;
 3829            }
 3830            2 => {
 3831                let position = display_map
 3832                    .clip_point(position, Bias::Left)
 3833                    .to_offset(&display_map, Bias::Left);
 3834                let (range, _) = buffer.surrounding_word(position, None);
 3835                start = buffer.anchor_before(range.start);
 3836                end = buffer.anchor_before(range.end);
 3837                mode = SelectMode::Word(start..end);
 3838                auto_scroll = true;
 3839            }
 3840            3 => {
 3841                let position = display_map
 3842                    .clip_point(position, Bias::Left)
 3843                    .to_point(&display_map);
 3844                let line_start = display_map.prev_line_boundary(position).0;
 3845                let next_line_start = buffer.clip_point(
 3846                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3847                    Bias::Left,
 3848                );
 3849                start = buffer.anchor_before(line_start);
 3850                end = buffer.anchor_before(next_line_start);
 3851                mode = SelectMode::Line(start..end);
 3852                auto_scroll = true;
 3853            }
 3854            _ => {
 3855                start = buffer.anchor_before(MultiBufferOffset(0));
 3856                end = buffer.anchor_before(buffer.len());
 3857                mode = SelectMode::All;
 3858                auto_scroll = false;
 3859            }
 3860        }
 3861        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3862
 3863        let point_to_delete: Option<usize> = {
 3864            let selected_points: Vec<Selection<Point>> =
 3865                self.selections.disjoint_in_range(start..end, &display_map);
 3866
 3867            if !add || click_count > 1 {
 3868                None
 3869            } else if !selected_points.is_empty() {
 3870                Some(selected_points[0].id)
 3871            } else {
 3872                let clicked_point_already_selected =
 3873                    self.selections.disjoint_anchors().iter().find(|selection| {
 3874                        selection.start.to_point(buffer) == start.to_point(buffer)
 3875                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3876                    });
 3877
 3878                clicked_point_already_selected.map(|selection| selection.id)
 3879            }
 3880        };
 3881
 3882        let selections_count = self.selections.count();
 3883        let effects = if auto_scroll {
 3884            SelectionEffects::default()
 3885        } else {
 3886            SelectionEffects::no_scroll()
 3887        };
 3888
 3889        self.change_selections(effects, window, cx, |s| {
 3890            if let Some(point_to_delete) = point_to_delete {
 3891                s.delete(point_to_delete);
 3892
 3893                if selections_count == 1 {
 3894                    s.set_pending_anchor_range(start..end, mode);
 3895                }
 3896            } else {
 3897                if !add {
 3898                    s.clear_disjoint();
 3899                }
 3900
 3901                s.set_pending_anchor_range(start..end, mode);
 3902            }
 3903        });
 3904    }
 3905
 3906    fn begin_columnar_selection(
 3907        &mut self,
 3908        position: DisplayPoint,
 3909        goal_column: u32,
 3910        reset: bool,
 3911        mode: ColumnarMode,
 3912        window: &mut Window,
 3913        cx: &mut Context<Self>,
 3914    ) {
 3915        if !self.focus_handle.is_focused(window) {
 3916            self.last_focused_descendant = None;
 3917            window.focus(&self.focus_handle);
 3918        }
 3919
 3920        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3921
 3922        if reset {
 3923            let pointer_position = display_map
 3924                .buffer_snapshot()
 3925                .anchor_before(position.to_point(&display_map));
 3926
 3927            self.change_selections(
 3928                SelectionEffects::scroll(Autoscroll::newest()),
 3929                window,
 3930                cx,
 3931                |s| {
 3932                    s.clear_disjoint();
 3933                    s.set_pending_anchor_range(
 3934                        pointer_position..pointer_position,
 3935                        SelectMode::Character,
 3936                    );
 3937                },
 3938            );
 3939        };
 3940
 3941        let tail = self.selections.newest::<Point>(&display_map).tail();
 3942        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3943        self.columnar_selection_state = match mode {
 3944            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3945                selection_tail: selection_anchor,
 3946                display_point: if reset {
 3947                    if position.column() != goal_column {
 3948                        Some(DisplayPoint::new(position.row(), goal_column))
 3949                    } else {
 3950                        None
 3951                    }
 3952                } else {
 3953                    None
 3954                },
 3955            }),
 3956            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3957                selection_tail: selection_anchor,
 3958            }),
 3959        };
 3960
 3961        if !reset {
 3962            self.select_columns(position, goal_column, &display_map, window, cx);
 3963        }
 3964    }
 3965
 3966    fn update_selection(
 3967        &mut self,
 3968        position: DisplayPoint,
 3969        goal_column: u32,
 3970        scroll_delta: gpui::Point<f32>,
 3971        window: &mut Window,
 3972        cx: &mut Context<Self>,
 3973    ) {
 3974        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3975
 3976        if self.columnar_selection_state.is_some() {
 3977            self.select_columns(position, goal_column, &display_map, window, cx);
 3978        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3979            let buffer = display_map.buffer_snapshot();
 3980            let head;
 3981            let tail;
 3982            let mode = self.selections.pending_mode().unwrap();
 3983            match &mode {
 3984                SelectMode::Character => {
 3985                    head = position.to_point(&display_map);
 3986                    tail = pending.tail().to_point(buffer);
 3987                }
 3988                SelectMode::Word(original_range) => {
 3989                    let offset = display_map
 3990                        .clip_point(position, Bias::Left)
 3991                        .to_offset(&display_map, Bias::Left);
 3992                    let original_range = original_range.to_offset(buffer);
 3993
 3994                    let head_offset = if buffer.is_inside_word(offset, None)
 3995                        || original_range.contains(&offset)
 3996                    {
 3997                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3998                        if word_range.start < original_range.start {
 3999                            word_range.start
 4000                        } else {
 4001                            word_range.end
 4002                        }
 4003                    } else {
 4004                        offset
 4005                    };
 4006
 4007                    head = head_offset.to_point(buffer);
 4008                    if head_offset <= original_range.start {
 4009                        tail = original_range.end.to_point(buffer);
 4010                    } else {
 4011                        tail = original_range.start.to_point(buffer);
 4012                    }
 4013                }
 4014                SelectMode::Line(original_range) => {
 4015                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4016
 4017                    let position = display_map
 4018                        .clip_point(position, Bias::Left)
 4019                        .to_point(&display_map);
 4020                    let line_start = display_map.prev_line_boundary(position).0;
 4021                    let next_line_start = buffer.clip_point(
 4022                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4023                        Bias::Left,
 4024                    );
 4025
 4026                    if line_start < original_range.start {
 4027                        head = line_start
 4028                    } else {
 4029                        head = next_line_start
 4030                    }
 4031
 4032                    if head <= original_range.start {
 4033                        tail = original_range.end;
 4034                    } else {
 4035                        tail = original_range.start;
 4036                    }
 4037                }
 4038                SelectMode::All => {
 4039                    return;
 4040                }
 4041            };
 4042
 4043            if head < tail {
 4044                pending.start = buffer.anchor_before(head);
 4045                pending.end = buffer.anchor_before(tail);
 4046                pending.reversed = true;
 4047            } else {
 4048                pending.start = buffer.anchor_before(tail);
 4049                pending.end = buffer.anchor_before(head);
 4050                pending.reversed = false;
 4051            }
 4052
 4053            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4054                s.set_pending(pending.clone(), mode);
 4055            });
 4056        } else {
 4057            log::error!("update_selection dispatched with no pending selection");
 4058            return;
 4059        }
 4060
 4061        self.apply_scroll_delta(scroll_delta, window, cx);
 4062        cx.notify();
 4063    }
 4064
 4065    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4066        self.columnar_selection_state.take();
 4067        if let Some(pending_mode) = self.selections.pending_mode() {
 4068            let selections = self
 4069                .selections
 4070                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4071            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4072                s.select(selections);
 4073                s.clear_pending();
 4074                if s.is_extending() {
 4075                    s.set_is_extending(false);
 4076                } else {
 4077                    s.set_select_mode(pending_mode);
 4078                }
 4079            });
 4080        }
 4081    }
 4082
 4083    fn select_columns(
 4084        &mut self,
 4085        head: DisplayPoint,
 4086        goal_column: u32,
 4087        display_map: &DisplaySnapshot,
 4088        window: &mut Window,
 4089        cx: &mut Context<Self>,
 4090    ) {
 4091        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4092            return;
 4093        };
 4094
 4095        let tail = match columnar_state {
 4096            ColumnarSelectionState::FromMouse {
 4097                selection_tail,
 4098                display_point,
 4099            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4100            ColumnarSelectionState::FromSelection { selection_tail } => {
 4101                selection_tail.to_display_point(display_map)
 4102            }
 4103        };
 4104
 4105        let start_row = cmp::min(tail.row(), head.row());
 4106        let end_row = cmp::max(tail.row(), head.row());
 4107        let start_column = cmp::min(tail.column(), goal_column);
 4108        let end_column = cmp::max(tail.column(), goal_column);
 4109        let reversed = start_column < tail.column();
 4110
 4111        let selection_ranges = (start_row.0..=end_row.0)
 4112            .map(DisplayRow)
 4113            .filter_map(|row| {
 4114                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4115                    || start_column <= display_map.line_len(row))
 4116                    && !display_map.is_block_line(row)
 4117                {
 4118                    let start = display_map
 4119                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4120                        .to_point(display_map);
 4121                    let end = display_map
 4122                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4123                        .to_point(display_map);
 4124                    if reversed {
 4125                        Some(end..start)
 4126                    } else {
 4127                        Some(start..end)
 4128                    }
 4129                } else {
 4130                    None
 4131                }
 4132            })
 4133            .collect::<Vec<_>>();
 4134        if selection_ranges.is_empty() {
 4135            return;
 4136        }
 4137
 4138        let ranges = match columnar_state {
 4139            ColumnarSelectionState::FromMouse { .. } => {
 4140                let mut non_empty_ranges = selection_ranges
 4141                    .iter()
 4142                    .filter(|selection_range| selection_range.start != selection_range.end)
 4143                    .peekable();
 4144                if non_empty_ranges.peek().is_some() {
 4145                    non_empty_ranges.cloned().collect()
 4146                } else {
 4147                    selection_ranges
 4148                }
 4149            }
 4150            _ => selection_ranges,
 4151        };
 4152
 4153        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4154            s.select_ranges(ranges);
 4155        });
 4156        cx.notify();
 4157    }
 4158
 4159    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4160        self.selections
 4161            .all_adjusted(snapshot)
 4162            .iter()
 4163            .any(|selection| !selection.is_empty())
 4164    }
 4165
 4166    pub fn has_pending_nonempty_selection(&self) -> bool {
 4167        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4168            Some(Selection { start, end, .. }) => start != end,
 4169            None => false,
 4170        };
 4171
 4172        pending_nonempty_selection
 4173            || (self.columnar_selection_state.is_some()
 4174                && self.selections.disjoint_anchors().len() > 1)
 4175    }
 4176
 4177    pub fn has_pending_selection(&self) -> bool {
 4178        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4179    }
 4180
 4181    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4182        self.selection_mark_mode = false;
 4183        self.selection_drag_state = SelectionDragState::None;
 4184
 4185        if self.dismiss_menus_and_popups(true, window, cx) {
 4186            cx.notify();
 4187            return;
 4188        }
 4189        if self.clear_expanded_diff_hunks(cx) {
 4190            cx.notify();
 4191            return;
 4192        }
 4193        if self.show_git_blame_gutter {
 4194            self.show_git_blame_gutter = false;
 4195            cx.notify();
 4196            return;
 4197        }
 4198
 4199        if self.mode.is_full()
 4200            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4201        {
 4202            cx.notify();
 4203            return;
 4204        }
 4205
 4206        cx.propagate();
 4207    }
 4208
 4209    pub fn dismiss_menus_and_popups(
 4210        &mut self,
 4211        is_user_requested: bool,
 4212        window: &mut Window,
 4213        cx: &mut Context<Self>,
 4214    ) -> bool {
 4215        let mut dismissed = false;
 4216
 4217        dismissed |= self.take_rename(false, window, cx).is_some();
 4218        dismissed |= self.hide_blame_popover(true, cx);
 4219        dismissed |= hide_hover(self, cx);
 4220        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4221        dismissed |= self.hide_context_menu(window, cx).is_some();
 4222        dismissed |= self.mouse_context_menu.take().is_some();
 4223        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4224        dismissed |= self.snippet_stack.pop().is_some();
 4225
 4226        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4227            self.dismiss_diagnostics(cx);
 4228            dismissed = true;
 4229        }
 4230
 4231        dismissed
 4232    }
 4233
 4234    fn linked_editing_ranges_for(
 4235        &self,
 4236        selection: Range<text::Anchor>,
 4237        cx: &App,
 4238    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4239        if self.linked_edit_ranges.is_empty() {
 4240            return None;
 4241        }
 4242        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4243            selection.end.buffer_id.and_then(|end_buffer_id| {
 4244                if selection.start.buffer_id != Some(end_buffer_id) {
 4245                    return None;
 4246                }
 4247                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4248                let snapshot = buffer.read(cx).snapshot();
 4249                self.linked_edit_ranges
 4250                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4251                    .map(|ranges| (ranges, snapshot, buffer))
 4252            })?;
 4253        use text::ToOffset as TO;
 4254        // find offset from the start of current range to current cursor position
 4255        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4256
 4257        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4258        let start_difference = start_offset - start_byte_offset;
 4259        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4260        let end_difference = end_offset - start_byte_offset;
 4261        // Current range has associated linked ranges.
 4262        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4263        for range in linked_ranges.iter() {
 4264            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4265            let end_offset = start_offset + end_difference;
 4266            let start_offset = start_offset + start_difference;
 4267            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4268                continue;
 4269            }
 4270            if self.selections.disjoint_anchor_ranges().any(|s| {
 4271                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4272                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4273                {
 4274                    return false;
 4275                }
 4276                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4277                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4278            }) {
 4279                continue;
 4280            }
 4281            let start = buffer_snapshot.anchor_after(start_offset);
 4282            let end = buffer_snapshot.anchor_after(end_offset);
 4283            linked_edits
 4284                .entry(buffer.clone())
 4285                .or_default()
 4286                .push(start..end);
 4287        }
 4288        Some(linked_edits)
 4289    }
 4290
 4291    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4292        let text: Arc<str> = text.into();
 4293
 4294        if self.read_only(cx) {
 4295            return;
 4296        }
 4297
 4298        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4299
 4300        self.unfold_buffers_with_selections(cx);
 4301
 4302        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4303        let mut bracket_inserted = false;
 4304        let mut edits = Vec::new();
 4305        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4306        let mut new_selections = Vec::with_capacity(selections.len());
 4307        let mut new_autoclose_regions = Vec::new();
 4308        let snapshot = self.buffer.read(cx).read(cx);
 4309        let mut clear_linked_edit_ranges = false;
 4310
 4311        for (selection, autoclose_region) in
 4312            self.selections_with_autoclose_regions(selections, &snapshot)
 4313        {
 4314            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4315                // Determine if the inserted text matches the opening or closing
 4316                // bracket of any of this language's bracket pairs.
 4317                let mut bracket_pair = None;
 4318                let mut is_bracket_pair_start = false;
 4319                let mut is_bracket_pair_end = false;
 4320                if !text.is_empty() {
 4321                    let mut bracket_pair_matching_end = None;
 4322                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4323                    //  and they are removing the character that triggered IME popup.
 4324                    for (pair, enabled) in scope.brackets() {
 4325                        if !pair.close && !pair.surround {
 4326                            continue;
 4327                        }
 4328
 4329                        if enabled && pair.start.ends_with(text.as_ref()) {
 4330                            let prefix_len = pair.start.len() - text.len();
 4331                            let preceding_text_matches_prefix = prefix_len == 0
 4332                                || (selection.start.column >= (prefix_len as u32)
 4333                                    && snapshot.contains_str_at(
 4334                                        Point::new(
 4335                                            selection.start.row,
 4336                                            selection.start.column - (prefix_len as u32),
 4337                                        ),
 4338                                        &pair.start[..prefix_len],
 4339                                    ));
 4340                            if preceding_text_matches_prefix {
 4341                                bracket_pair = Some(pair.clone());
 4342                                is_bracket_pair_start = true;
 4343                                break;
 4344                            }
 4345                        }
 4346                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4347                        {
 4348                            // take first bracket pair matching end, but don't break in case a later bracket
 4349                            // pair matches start
 4350                            bracket_pair_matching_end = Some(pair.clone());
 4351                        }
 4352                    }
 4353                    if let Some(end) = bracket_pair_matching_end
 4354                        && bracket_pair.is_none()
 4355                    {
 4356                        bracket_pair = Some(end);
 4357                        is_bracket_pair_end = true;
 4358                    }
 4359                }
 4360
 4361                if let Some(bracket_pair) = bracket_pair {
 4362                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4363                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4364                    let auto_surround =
 4365                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4366                    if selection.is_empty() {
 4367                        if is_bracket_pair_start {
 4368                            // If the inserted text is a suffix of an opening bracket and the
 4369                            // selection is preceded by the rest of the opening bracket, then
 4370                            // insert the closing bracket.
 4371                            let following_text_allows_autoclose = snapshot
 4372                                .chars_at(selection.start)
 4373                                .next()
 4374                                .is_none_or(|c| scope.should_autoclose_before(c));
 4375
 4376                            let preceding_text_allows_autoclose = selection.start.column == 0
 4377                                || snapshot
 4378                                    .reversed_chars_at(selection.start)
 4379                                    .next()
 4380                                    .is_none_or(|c| {
 4381                                        bracket_pair.start != bracket_pair.end
 4382                                            || !snapshot
 4383                                                .char_classifier_at(selection.start)
 4384                                                .is_word(c)
 4385                                    });
 4386
 4387                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4388                                && bracket_pair.start.len() == 1
 4389                            {
 4390                                let target = bracket_pair.start.chars().next().unwrap();
 4391                                let current_line_count = snapshot
 4392                                    .reversed_chars_at(selection.start)
 4393                                    .take_while(|&c| c != '\n')
 4394                                    .filter(|&c| c == target)
 4395                                    .count();
 4396                                current_line_count % 2 == 1
 4397                            } else {
 4398                                false
 4399                            };
 4400
 4401                            if autoclose
 4402                                && bracket_pair.close
 4403                                && following_text_allows_autoclose
 4404                                && preceding_text_allows_autoclose
 4405                                && !is_closing_quote
 4406                            {
 4407                                let anchor = snapshot.anchor_before(selection.end);
 4408                                new_selections.push((selection.map(|_| anchor), text.len()));
 4409                                new_autoclose_regions.push((
 4410                                    anchor,
 4411                                    text.len(),
 4412                                    selection.id,
 4413                                    bracket_pair.clone(),
 4414                                ));
 4415                                edits.push((
 4416                                    selection.range(),
 4417                                    format!("{}{}", text, bracket_pair.end).into(),
 4418                                ));
 4419                                bracket_inserted = true;
 4420                                continue;
 4421                            }
 4422                        }
 4423
 4424                        if let Some(region) = autoclose_region {
 4425                            // If the selection is followed by an auto-inserted closing bracket,
 4426                            // then don't insert that closing bracket again; just move the selection
 4427                            // past the closing bracket.
 4428                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4429                                && text.as_ref() == region.pair.end.as_str()
 4430                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4431                            if should_skip {
 4432                                let anchor = snapshot.anchor_after(selection.end);
 4433                                new_selections
 4434                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4435                                continue;
 4436                            }
 4437                        }
 4438
 4439                        let always_treat_brackets_as_autoclosed = snapshot
 4440                            .language_settings_at(selection.start, cx)
 4441                            .always_treat_brackets_as_autoclosed;
 4442                        if always_treat_brackets_as_autoclosed
 4443                            && is_bracket_pair_end
 4444                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4445                        {
 4446                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4447                            // and the inserted text is a closing bracket and the selection is followed
 4448                            // by the closing bracket then move the selection past the closing bracket.
 4449                            let anchor = snapshot.anchor_after(selection.end);
 4450                            new_selections.push((selection.map(|_| anchor), text.len()));
 4451                            continue;
 4452                        }
 4453                    }
 4454                    // If an opening bracket is 1 character long and is typed while
 4455                    // text is selected, then surround that text with the bracket pair.
 4456                    else if auto_surround
 4457                        && bracket_pair.surround
 4458                        && is_bracket_pair_start
 4459                        && bracket_pair.start.chars().count() == 1
 4460                    {
 4461                        edits.push((selection.start..selection.start, text.clone()));
 4462                        edits.push((
 4463                            selection.end..selection.end,
 4464                            bracket_pair.end.as_str().into(),
 4465                        ));
 4466                        bracket_inserted = true;
 4467                        new_selections.push((
 4468                            Selection {
 4469                                id: selection.id,
 4470                                start: snapshot.anchor_after(selection.start),
 4471                                end: snapshot.anchor_before(selection.end),
 4472                                reversed: selection.reversed,
 4473                                goal: selection.goal,
 4474                            },
 4475                            0,
 4476                        ));
 4477                        continue;
 4478                    }
 4479                }
 4480            }
 4481
 4482            if self.auto_replace_emoji_shortcode
 4483                && selection.is_empty()
 4484                && text.as_ref().ends_with(':')
 4485                && let Some(possible_emoji_short_code) =
 4486                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4487                && !possible_emoji_short_code.is_empty()
 4488                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4489            {
 4490                let emoji_shortcode_start = Point::new(
 4491                    selection.start.row,
 4492                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4493                );
 4494
 4495                // Remove shortcode from buffer
 4496                edits.push((
 4497                    emoji_shortcode_start..selection.start,
 4498                    "".to_string().into(),
 4499                ));
 4500                new_selections.push((
 4501                    Selection {
 4502                        id: selection.id,
 4503                        start: snapshot.anchor_after(emoji_shortcode_start),
 4504                        end: snapshot.anchor_before(selection.start),
 4505                        reversed: selection.reversed,
 4506                        goal: selection.goal,
 4507                    },
 4508                    0,
 4509                ));
 4510
 4511                // Insert emoji
 4512                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4513                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4514                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4515
 4516                continue;
 4517            }
 4518
 4519            // If not handling any auto-close operation, then just replace the selected
 4520            // text with the given input and move the selection to the end of the
 4521            // newly inserted text.
 4522            let anchor = snapshot.anchor_after(selection.end);
 4523            if !self.linked_edit_ranges.is_empty() {
 4524                let start_anchor = snapshot.anchor_before(selection.start);
 4525
 4526                let is_word_char = text.chars().next().is_none_or(|char| {
 4527                    let classifier = snapshot
 4528                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4529                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4530                    classifier.is_word(char)
 4531                });
 4532
 4533                if is_word_char {
 4534                    if let Some(ranges) = self
 4535                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4536                    {
 4537                        for (buffer, edits) in ranges {
 4538                            linked_edits
 4539                                .entry(buffer.clone())
 4540                                .or_default()
 4541                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4542                        }
 4543                    }
 4544                } else {
 4545                    clear_linked_edit_ranges = true;
 4546                }
 4547            }
 4548
 4549            new_selections.push((selection.map(|_| anchor), 0));
 4550            edits.push((selection.start..selection.end, text.clone()));
 4551        }
 4552
 4553        drop(snapshot);
 4554
 4555        self.transact(window, cx, |this, window, cx| {
 4556            if clear_linked_edit_ranges {
 4557                this.linked_edit_ranges.clear();
 4558            }
 4559            let initial_buffer_versions =
 4560                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4561
 4562            this.buffer.update(cx, |buffer, cx| {
 4563                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4564            });
 4565            for (buffer, edits) in linked_edits {
 4566                buffer.update(cx, |buffer, cx| {
 4567                    let snapshot = buffer.snapshot();
 4568                    let edits = edits
 4569                        .into_iter()
 4570                        .map(|(range, text)| {
 4571                            use text::ToPoint as TP;
 4572                            let end_point = TP::to_point(&range.end, &snapshot);
 4573                            let start_point = TP::to_point(&range.start, &snapshot);
 4574                            (start_point..end_point, text)
 4575                        })
 4576                        .sorted_by_key(|(range, _)| range.start);
 4577                    buffer.edit(edits, None, cx);
 4578                })
 4579            }
 4580            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4581            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4582            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4583            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4584                new_anchor_selections,
 4585                &map,
 4586            )
 4587            .zip(new_selection_deltas)
 4588            .map(|(selection, delta)| Selection {
 4589                id: selection.id,
 4590                start: selection.start + delta,
 4591                end: selection.end + delta,
 4592                reversed: selection.reversed,
 4593                goal: SelectionGoal::None,
 4594            })
 4595            .collect::<Vec<_>>();
 4596
 4597            let mut i = 0;
 4598            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4599                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4600                let start = map.buffer_snapshot().anchor_before(position);
 4601                let end = map.buffer_snapshot().anchor_after(position);
 4602                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4603                    match existing_state
 4604                        .range
 4605                        .start
 4606                        .cmp(&start, map.buffer_snapshot())
 4607                    {
 4608                        Ordering::Less => i += 1,
 4609                        Ordering::Greater => break,
 4610                        Ordering::Equal => {
 4611                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4612                                Ordering::Less => i += 1,
 4613                                Ordering::Equal => break,
 4614                                Ordering::Greater => break,
 4615                            }
 4616                        }
 4617                    }
 4618                }
 4619                this.autoclose_regions.insert(
 4620                    i,
 4621                    AutocloseRegion {
 4622                        selection_id,
 4623                        range: start..end,
 4624                        pair,
 4625                    },
 4626                );
 4627            }
 4628
 4629            let had_active_edit_prediction = this.has_active_edit_prediction();
 4630            this.change_selections(
 4631                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4632                window,
 4633                cx,
 4634                |s| s.select(new_selections),
 4635            );
 4636
 4637            if !bracket_inserted
 4638                && let Some(on_type_format_task) =
 4639                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4640            {
 4641                on_type_format_task.detach_and_log_err(cx);
 4642            }
 4643
 4644            let editor_settings = EditorSettings::get_global(cx);
 4645            if bracket_inserted
 4646                && (editor_settings.auto_signature_help
 4647                    || editor_settings.show_signature_help_after_edits)
 4648            {
 4649                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4650            }
 4651
 4652            let trigger_in_words =
 4653                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4654            if this.hard_wrap.is_some() {
 4655                let latest: Range<Point> = this.selections.newest(&map).range();
 4656                if latest.is_empty()
 4657                    && this
 4658                        .buffer()
 4659                        .read(cx)
 4660                        .snapshot(cx)
 4661                        .line_len(MultiBufferRow(latest.start.row))
 4662                        == latest.start.column
 4663                {
 4664                    this.rewrap_impl(
 4665                        RewrapOptions {
 4666                            override_language_settings: true,
 4667                            preserve_existing_whitespace: true,
 4668                        },
 4669                        cx,
 4670                    )
 4671                }
 4672            }
 4673            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4674            refresh_linked_ranges(this, window, cx);
 4675            this.refresh_edit_prediction(true, false, window, cx);
 4676            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4677        });
 4678    }
 4679
 4680    fn find_possible_emoji_shortcode_at_position(
 4681        snapshot: &MultiBufferSnapshot,
 4682        position: Point,
 4683    ) -> Option<String> {
 4684        let mut chars = Vec::new();
 4685        let mut found_colon = false;
 4686        for char in snapshot.reversed_chars_at(position).take(100) {
 4687            // Found a possible emoji shortcode in the middle of the buffer
 4688            if found_colon {
 4689                if char.is_whitespace() {
 4690                    chars.reverse();
 4691                    return Some(chars.iter().collect());
 4692                }
 4693                // If the previous character is not a whitespace, we are in the middle of a word
 4694                // and we only want to complete the shortcode if the word is made up of other emojis
 4695                let mut containing_word = String::new();
 4696                for ch in snapshot
 4697                    .reversed_chars_at(position)
 4698                    .skip(chars.len() + 1)
 4699                    .take(100)
 4700                {
 4701                    if ch.is_whitespace() {
 4702                        break;
 4703                    }
 4704                    containing_word.push(ch);
 4705                }
 4706                let containing_word = containing_word.chars().rev().collect::<String>();
 4707                if util::word_consists_of_emojis(containing_word.as_str()) {
 4708                    chars.reverse();
 4709                    return Some(chars.iter().collect());
 4710                }
 4711            }
 4712
 4713            if char.is_whitespace() || !char.is_ascii() {
 4714                return None;
 4715            }
 4716            if char == ':' {
 4717                found_colon = true;
 4718            } else {
 4719                chars.push(char);
 4720            }
 4721        }
 4722        // Found a possible emoji shortcode at the beginning of the buffer
 4723        chars.reverse();
 4724        Some(chars.iter().collect())
 4725    }
 4726
 4727    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4728        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4729        self.transact(window, cx, |this, window, cx| {
 4730            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4731                let selections = this
 4732                    .selections
 4733                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4734                let multi_buffer = this.buffer.read(cx);
 4735                let buffer = multi_buffer.snapshot(cx);
 4736                selections
 4737                    .iter()
 4738                    .map(|selection| {
 4739                        let start_point = selection.start.to_point(&buffer);
 4740                        let mut existing_indent =
 4741                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4742                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4743                        let start = selection.start;
 4744                        let end = selection.end;
 4745                        let selection_is_empty = start == end;
 4746                        let language_scope = buffer.language_scope_at(start);
 4747                        let (
 4748                            comment_delimiter,
 4749                            doc_delimiter,
 4750                            insert_extra_newline,
 4751                            indent_on_newline,
 4752                            indent_on_extra_newline,
 4753                        ) = if let Some(language) = &language_scope {
 4754                            let mut insert_extra_newline =
 4755                                insert_extra_newline_brackets(&buffer, start..end, language)
 4756                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4757
 4758                            // Comment extension on newline is allowed only for cursor selections
 4759                            let comment_delimiter = maybe!({
 4760                                if !selection_is_empty {
 4761                                    return None;
 4762                                }
 4763
 4764                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4765                                    return None;
 4766                                }
 4767
 4768                                let delimiters = language.line_comment_prefixes();
 4769                                let max_len_of_delimiter =
 4770                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4771                                let (snapshot, range) =
 4772                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4773
 4774                                let num_of_whitespaces = snapshot
 4775                                    .chars_for_range(range.clone())
 4776                                    .take_while(|c| c.is_whitespace())
 4777                                    .count();
 4778                                let comment_candidate = snapshot
 4779                                    .chars_for_range(range.clone())
 4780                                    .skip(num_of_whitespaces)
 4781                                    .take(max_len_of_delimiter)
 4782                                    .collect::<String>();
 4783                                let (delimiter, trimmed_len) = delimiters
 4784                                    .iter()
 4785                                    .filter_map(|delimiter| {
 4786                                        let prefix = delimiter.trim_end();
 4787                                        if comment_candidate.starts_with(prefix) {
 4788                                            Some((delimiter, prefix.len()))
 4789                                        } else {
 4790                                            None
 4791                                        }
 4792                                    })
 4793                                    .max_by_key(|(_, len)| *len)?;
 4794
 4795                                if let Some(BlockCommentConfig {
 4796                                    start: block_start, ..
 4797                                }) = language.block_comment()
 4798                                {
 4799                                    let block_start_trimmed = block_start.trim_end();
 4800                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4801                                        let line_content = snapshot
 4802                                            .chars_for_range(range)
 4803                                            .skip(num_of_whitespaces)
 4804                                            .take(block_start_trimmed.len())
 4805                                            .collect::<String>();
 4806
 4807                                        if line_content.starts_with(block_start_trimmed) {
 4808                                            return None;
 4809                                        }
 4810                                    }
 4811                                }
 4812
 4813                                let cursor_is_placed_after_comment_marker =
 4814                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4815                                if cursor_is_placed_after_comment_marker {
 4816                                    Some(delimiter.clone())
 4817                                } else {
 4818                                    None
 4819                                }
 4820                            });
 4821
 4822                            let mut indent_on_newline = IndentSize::spaces(0);
 4823                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4824
 4825                            let doc_delimiter = maybe!({
 4826                                if !selection_is_empty {
 4827                                    return None;
 4828                                }
 4829
 4830                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4831                                    return None;
 4832                                }
 4833
 4834                                let BlockCommentConfig {
 4835                                    start: start_tag,
 4836                                    end: end_tag,
 4837                                    prefix: delimiter,
 4838                                    tab_size: len,
 4839                                } = language.documentation_comment()?;
 4840                                let is_within_block_comment = buffer
 4841                                    .language_scope_at(start_point)
 4842                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4843                                if !is_within_block_comment {
 4844                                    return None;
 4845                                }
 4846
 4847                                let (snapshot, range) =
 4848                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4849
 4850                                let num_of_whitespaces = snapshot
 4851                                    .chars_for_range(range.clone())
 4852                                    .take_while(|c| c.is_whitespace())
 4853                                    .count();
 4854
 4855                                // 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.
 4856                                let column = start_point.column;
 4857                                let cursor_is_after_start_tag = {
 4858                                    let start_tag_len = start_tag.len();
 4859                                    let start_tag_line = snapshot
 4860                                        .chars_for_range(range.clone())
 4861                                        .skip(num_of_whitespaces)
 4862                                        .take(start_tag_len)
 4863                                        .collect::<String>();
 4864                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4865                                        num_of_whitespaces + start_tag_len <= column as usize
 4866                                    } else {
 4867                                        false
 4868                                    }
 4869                                };
 4870
 4871                                let cursor_is_after_delimiter = {
 4872                                    let delimiter_trim = delimiter.trim_end();
 4873                                    let delimiter_line = snapshot
 4874                                        .chars_for_range(range.clone())
 4875                                        .skip(num_of_whitespaces)
 4876                                        .take(delimiter_trim.len())
 4877                                        .collect::<String>();
 4878                                    if delimiter_line.starts_with(delimiter_trim) {
 4879                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4880                                    } else {
 4881                                        false
 4882                                    }
 4883                                };
 4884
 4885                                let cursor_is_before_end_tag_if_exists = {
 4886                                    let mut char_position = 0u32;
 4887                                    let mut end_tag_offset = None;
 4888
 4889                                    'outer: for chunk in snapshot.text_for_range(range) {
 4890                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4891                                            let chars_before_match =
 4892                                                chunk[..byte_pos].chars().count() as u32;
 4893                                            end_tag_offset =
 4894                                                Some(char_position + chars_before_match);
 4895                                            break 'outer;
 4896                                        }
 4897                                        char_position += chunk.chars().count() as u32;
 4898                                    }
 4899
 4900                                    if let Some(end_tag_offset) = end_tag_offset {
 4901                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4902                                        if cursor_is_after_start_tag {
 4903                                            if cursor_is_before_end_tag {
 4904                                                insert_extra_newline = true;
 4905                                            }
 4906                                            let cursor_is_at_start_of_end_tag =
 4907                                                column == end_tag_offset;
 4908                                            if cursor_is_at_start_of_end_tag {
 4909                                                indent_on_extra_newline.len = *len;
 4910                                            }
 4911                                        }
 4912                                        cursor_is_before_end_tag
 4913                                    } else {
 4914                                        true
 4915                                    }
 4916                                };
 4917
 4918                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4919                                    && cursor_is_before_end_tag_if_exists
 4920                                {
 4921                                    if cursor_is_after_start_tag {
 4922                                        indent_on_newline.len = *len;
 4923                                    }
 4924                                    Some(delimiter.clone())
 4925                                } else {
 4926                                    None
 4927                                }
 4928                            });
 4929
 4930                            (
 4931                                comment_delimiter,
 4932                                doc_delimiter,
 4933                                insert_extra_newline,
 4934                                indent_on_newline,
 4935                                indent_on_extra_newline,
 4936                            )
 4937                        } else {
 4938                            (
 4939                                None,
 4940                                None,
 4941                                false,
 4942                                IndentSize::default(),
 4943                                IndentSize::default(),
 4944                            )
 4945                        };
 4946
 4947                        let prevent_auto_indent = doc_delimiter.is_some();
 4948                        let delimiter = comment_delimiter.or(doc_delimiter);
 4949
 4950                        let capacity_for_delimiter =
 4951                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4952                        let mut new_text = String::with_capacity(
 4953                            1 + capacity_for_delimiter
 4954                                + existing_indent.len as usize
 4955                                + indent_on_newline.len as usize
 4956                                + indent_on_extra_newline.len as usize,
 4957                        );
 4958                        new_text.push('\n');
 4959                        new_text.extend(existing_indent.chars());
 4960                        new_text.extend(indent_on_newline.chars());
 4961
 4962                        if let Some(delimiter) = &delimiter {
 4963                            new_text.push_str(delimiter);
 4964                        }
 4965
 4966                        if insert_extra_newline {
 4967                            new_text.push('\n');
 4968                            new_text.extend(existing_indent.chars());
 4969                            new_text.extend(indent_on_extra_newline.chars());
 4970                        }
 4971
 4972                        let anchor = buffer.anchor_after(end);
 4973                        let new_selection = selection.map(|_| anchor);
 4974                        (
 4975                            ((start..end, new_text), prevent_auto_indent),
 4976                            (insert_extra_newline, new_selection),
 4977                        )
 4978                    })
 4979                    .unzip()
 4980            };
 4981
 4982            let mut auto_indent_edits = Vec::new();
 4983            let mut edits = Vec::new();
 4984            for (edit, prevent_auto_indent) in edits_with_flags {
 4985                if prevent_auto_indent {
 4986                    edits.push(edit);
 4987                } else {
 4988                    auto_indent_edits.push(edit);
 4989                }
 4990            }
 4991            if !edits.is_empty() {
 4992                this.edit(edits, cx);
 4993            }
 4994            if !auto_indent_edits.is_empty() {
 4995                this.edit_with_autoindent(auto_indent_edits, cx);
 4996            }
 4997
 4998            let buffer = this.buffer.read(cx).snapshot(cx);
 4999            let new_selections = selection_info
 5000                .into_iter()
 5001                .map(|(extra_newline_inserted, new_selection)| {
 5002                    let mut cursor = new_selection.end.to_point(&buffer);
 5003                    if extra_newline_inserted {
 5004                        cursor.row -= 1;
 5005                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5006                    }
 5007                    new_selection.map(|_| cursor)
 5008                })
 5009                .collect();
 5010
 5011            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5012            this.refresh_edit_prediction(true, false, window, cx);
 5013        });
 5014    }
 5015
 5016    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5017        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5018
 5019        let buffer = self.buffer.read(cx);
 5020        let snapshot = buffer.snapshot(cx);
 5021
 5022        let mut edits = Vec::new();
 5023        let mut rows = Vec::new();
 5024
 5025        for (rows_inserted, selection) in self
 5026            .selections
 5027            .all_adjusted(&self.display_snapshot(cx))
 5028            .into_iter()
 5029            .enumerate()
 5030        {
 5031            let cursor = selection.head();
 5032            let row = cursor.row;
 5033
 5034            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5035
 5036            let newline = "\n".to_string();
 5037            edits.push((start_of_line..start_of_line, newline));
 5038
 5039            rows.push(row + rows_inserted as u32);
 5040        }
 5041
 5042        self.transact(window, cx, |editor, window, cx| {
 5043            editor.edit(edits, cx);
 5044
 5045            editor.change_selections(Default::default(), window, cx, |s| {
 5046                let mut index = 0;
 5047                s.move_cursors_with(|map, _, _| {
 5048                    let row = rows[index];
 5049                    index += 1;
 5050
 5051                    let point = Point::new(row, 0);
 5052                    let boundary = map.next_line_boundary(point).1;
 5053                    let clipped = map.clip_point(boundary, Bias::Left);
 5054
 5055                    (clipped, SelectionGoal::None)
 5056                });
 5057            });
 5058
 5059            let mut indent_edits = Vec::new();
 5060            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5061            for row in rows {
 5062                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5063                for (row, indent) in indents {
 5064                    if indent.len == 0 {
 5065                        continue;
 5066                    }
 5067
 5068                    let text = match indent.kind {
 5069                        IndentKind::Space => " ".repeat(indent.len as usize),
 5070                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5071                    };
 5072                    let point = Point::new(row.0, 0);
 5073                    indent_edits.push((point..point, text));
 5074                }
 5075            }
 5076            editor.edit(indent_edits, cx);
 5077        });
 5078    }
 5079
 5080    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5081        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5082
 5083        let buffer = self.buffer.read(cx);
 5084        let snapshot = buffer.snapshot(cx);
 5085
 5086        let mut edits = Vec::new();
 5087        let mut rows = Vec::new();
 5088        let mut rows_inserted = 0;
 5089
 5090        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5091            let cursor = selection.head();
 5092            let row = cursor.row;
 5093
 5094            let point = Point::new(row + 1, 0);
 5095            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5096
 5097            let newline = "\n".to_string();
 5098            edits.push((start_of_line..start_of_line, newline));
 5099
 5100            rows_inserted += 1;
 5101            rows.push(row + rows_inserted);
 5102        }
 5103
 5104        self.transact(window, cx, |editor, window, cx| {
 5105            editor.edit(edits, cx);
 5106
 5107            editor.change_selections(Default::default(), window, cx, |s| {
 5108                let mut index = 0;
 5109                s.move_cursors_with(|map, _, _| {
 5110                    let row = rows[index];
 5111                    index += 1;
 5112
 5113                    let point = Point::new(row, 0);
 5114                    let boundary = map.next_line_boundary(point).1;
 5115                    let clipped = map.clip_point(boundary, Bias::Left);
 5116
 5117                    (clipped, SelectionGoal::None)
 5118                });
 5119            });
 5120
 5121            let mut indent_edits = Vec::new();
 5122            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5123            for row in rows {
 5124                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5125                for (row, indent) in indents {
 5126                    if indent.len == 0 {
 5127                        continue;
 5128                    }
 5129
 5130                    let text = match indent.kind {
 5131                        IndentKind::Space => " ".repeat(indent.len as usize),
 5132                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5133                    };
 5134                    let point = Point::new(row.0, 0);
 5135                    indent_edits.push((point..point, text));
 5136                }
 5137            }
 5138            editor.edit(indent_edits, cx);
 5139        });
 5140    }
 5141
 5142    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5143        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5144            original_indent_columns: Vec::new(),
 5145        });
 5146        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5147    }
 5148
 5149    fn insert_with_autoindent_mode(
 5150        &mut self,
 5151        text: &str,
 5152        autoindent_mode: Option<AutoindentMode>,
 5153        window: &mut Window,
 5154        cx: &mut Context<Self>,
 5155    ) {
 5156        if self.read_only(cx) {
 5157            return;
 5158        }
 5159
 5160        let text: Arc<str> = text.into();
 5161        self.transact(window, cx, |this, window, cx| {
 5162            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5163            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5164                let anchors = {
 5165                    let snapshot = buffer.read(cx);
 5166                    old_selections
 5167                        .iter()
 5168                        .map(|s| {
 5169                            let anchor = snapshot.anchor_after(s.head());
 5170                            s.map(|_| anchor)
 5171                        })
 5172                        .collect::<Vec<_>>()
 5173                };
 5174                buffer.edit(
 5175                    old_selections
 5176                        .iter()
 5177                        .map(|s| (s.start..s.end, text.clone())),
 5178                    autoindent_mode,
 5179                    cx,
 5180                );
 5181                anchors
 5182            });
 5183
 5184            this.change_selections(Default::default(), window, cx, |s| {
 5185                s.select_anchors(selection_anchors);
 5186            });
 5187
 5188            cx.notify();
 5189        });
 5190    }
 5191
 5192    fn trigger_completion_on_input(
 5193        &mut self,
 5194        text: &str,
 5195        trigger_in_words: bool,
 5196        window: &mut Window,
 5197        cx: &mut Context<Self>,
 5198    ) {
 5199        let completions_source = self
 5200            .context_menu
 5201            .borrow()
 5202            .as_ref()
 5203            .and_then(|menu| match menu {
 5204                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5205                CodeContextMenu::CodeActions(_) => None,
 5206            });
 5207
 5208        match completions_source {
 5209            Some(CompletionsMenuSource::Words { .. }) => {
 5210                self.open_or_update_completions_menu(
 5211                    Some(CompletionsMenuSource::Words {
 5212                        ignore_threshold: false,
 5213                    }),
 5214                    None,
 5215                    trigger_in_words,
 5216                    window,
 5217                    cx,
 5218                );
 5219            }
 5220            _ => self.open_or_update_completions_menu(
 5221                None,
 5222                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5223                true,
 5224                window,
 5225                cx,
 5226            ),
 5227        }
 5228    }
 5229
 5230    /// If any empty selections is touching the start of its innermost containing autoclose
 5231    /// region, expand it to select the brackets.
 5232    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5233        let selections = self
 5234            .selections
 5235            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5236        let buffer = self.buffer.read(cx).read(cx);
 5237        let new_selections = self
 5238            .selections_with_autoclose_regions(selections, &buffer)
 5239            .map(|(mut selection, region)| {
 5240                if !selection.is_empty() {
 5241                    return selection;
 5242                }
 5243
 5244                if let Some(region) = region {
 5245                    let mut range = region.range.to_offset(&buffer);
 5246                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5247                        range.start -= region.pair.start.len();
 5248                        if buffer.contains_str_at(range.start, &region.pair.start)
 5249                            && buffer.contains_str_at(range.end, &region.pair.end)
 5250                        {
 5251                            range.end += region.pair.end.len();
 5252                            selection.start = range.start;
 5253                            selection.end = range.end;
 5254
 5255                            return selection;
 5256                        }
 5257                    }
 5258                }
 5259
 5260                let always_treat_brackets_as_autoclosed = buffer
 5261                    .language_settings_at(selection.start, cx)
 5262                    .always_treat_brackets_as_autoclosed;
 5263
 5264                if !always_treat_brackets_as_autoclosed {
 5265                    return selection;
 5266                }
 5267
 5268                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5269                    for (pair, enabled) in scope.brackets() {
 5270                        if !enabled || !pair.close {
 5271                            continue;
 5272                        }
 5273
 5274                        if buffer.contains_str_at(selection.start, &pair.end) {
 5275                            let pair_start_len = pair.start.len();
 5276                            if buffer.contains_str_at(
 5277                                selection.start.saturating_sub_usize(pair_start_len),
 5278                                &pair.start,
 5279                            ) {
 5280                                selection.start -= pair_start_len;
 5281                                selection.end += pair.end.len();
 5282
 5283                                return selection;
 5284                            }
 5285                        }
 5286                    }
 5287                }
 5288
 5289                selection
 5290            })
 5291            .collect();
 5292
 5293        drop(buffer);
 5294        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5295            selections.select(new_selections)
 5296        });
 5297    }
 5298
 5299    /// Iterate the given selections, and for each one, find the smallest surrounding
 5300    /// autoclose region. This uses the ordering of the selections and the autoclose
 5301    /// regions to avoid repeated comparisons.
 5302    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5303        &'a self,
 5304        selections: impl IntoIterator<Item = Selection<D>>,
 5305        buffer: &'a MultiBufferSnapshot,
 5306    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5307        let mut i = 0;
 5308        let mut regions = self.autoclose_regions.as_slice();
 5309        selections.into_iter().map(move |selection| {
 5310            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5311
 5312            let mut enclosing = None;
 5313            while let Some(pair_state) = regions.get(i) {
 5314                if pair_state.range.end.to_offset(buffer) < range.start {
 5315                    regions = &regions[i + 1..];
 5316                    i = 0;
 5317                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5318                    break;
 5319                } else {
 5320                    if pair_state.selection_id == selection.id {
 5321                        enclosing = Some(pair_state);
 5322                    }
 5323                    i += 1;
 5324                }
 5325            }
 5326
 5327            (selection, enclosing)
 5328        })
 5329    }
 5330
 5331    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5332    fn invalidate_autoclose_regions(
 5333        &mut self,
 5334        mut selections: &[Selection<Anchor>],
 5335        buffer: &MultiBufferSnapshot,
 5336    ) {
 5337        self.autoclose_regions.retain(|state| {
 5338            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5339                return false;
 5340            }
 5341
 5342            let mut i = 0;
 5343            while let Some(selection) = selections.get(i) {
 5344                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5345                    selections = &selections[1..];
 5346                    continue;
 5347                }
 5348                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5349                    break;
 5350                }
 5351                if selection.id == state.selection_id {
 5352                    return true;
 5353                } else {
 5354                    i += 1;
 5355                }
 5356            }
 5357            false
 5358        });
 5359    }
 5360
 5361    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5362        let offset = position.to_offset(buffer);
 5363        let (word_range, kind) =
 5364            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5365        if offset > word_range.start && kind == Some(CharKind::Word) {
 5366            Some(
 5367                buffer
 5368                    .text_for_range(word_range.start..offset)
 5369                    .collect::<String>(),
 5370            )
 5371        } else {
 5372            None
 5373        }
 5374    }
 5375
 5376    pub fn visible_excerpts(
 5377        &self,
 5378        lsp_related_only: bool,
 5379        cx: &mut Context<Editor>,
 5380    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5381        let project = self.project().cloned();
 5382        let multi_buffer = self.buffer().read(cx);
 5383        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5384        let multi_buffer_visible_start = self
 5385            .scroll_manager
 5386            .anchor()
 5387            .anchor
 5388            .to_point(&multi_buffer_snapshot);
 5389        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5390            multi_buffer_visible_start
 5391                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5392            Bias::Left,
 5393        );
 5394        multi_buffer_snapshot
 5395            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5396            .into_iter()
 5397            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5398            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5399                if !lsp_related_only {
 5400                    return Some((
 5401                        excerpt_id,
 5402                        (
 5403                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5404                            buffer.version().clone(),
 5405                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5406                        ),
 5407                    ));
 5408                }
 5409
 5410                let project = project.as_ref()?.read(cx);
 5411                let buffer_file = project::File::from_dyn(buffer.file())?;
 5412                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5413                let worktree_entry = buffer_worktree
 5414                    .read(cx)
 5415                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5416                if worktree_entry.is_ignored {
 5417                    None
 5418                } else {
 5419                    Some((
 5420                        excerpt_id,
 5421                        (
 5422                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5423                            buffer.version().clone(),
 5424                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5425                        ),
 5426                    ))
 5427                }
 5428            })
 5429            .collect()
 5430    }
 5431
 5432    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5433        TextLayoutDetails {
 5434            text_system: window.text_system().clone(),
 5435            editor_style: self.style.clone().unwrap(),
 5436            rem_size: window.rem_size(),
 5437            scroll_anchor: self.scroll_manager.anchor(),
 5438            visible_rows: self.visible_line_count(),
 5439            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5440        }
 5441    }
 5442
 5443    fn trigger_on_type_formatting(
 5444        &self,
 5445        input: String,
 5446        window: &mut Window,
 5447        cx: &mut Context<Self>,
 5448    ) -> Option<Task<Result<()>>> {
 5449        if input.len() != 1 {
 5450            return None;
 5451        }
 5452
 5453        let project = self.project()?;
 5454        let position = self.selections.newest_anchor().head();
 5455        let (buffer, buffer_position) = self
 5456            .buffer
 5457            .read(cx)
 5458            .text_anchor_for_position(position, cx)?;
 5459
 5460        let settings = language_settings::language_settings(
 5461            buffer
 5462                .read(cx)
 5463                .language_at(buffer_position)
 5464                .map(|l| l.name()),
 5465            buffer.read(cx).file(),
 5466            cx,
 5467        );
 5468        if !settings.use_on_type_format {
 5469            return None;
 5470        }
 5471
 5472        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5473        // hence we do LSP request & edit on host side only — add formats to host's history.
 5474        let push_to_lsp_host_history = true;
 5475        // If this is not the host, append its history with new edits.
 5476        let push_to_client_history = project.read(cx).is_via_collab();
 5477
 5478        let on_type_formatting = project.update(cx, |project, cx| {
 5479            project.on_type_format(
 5480                buffer.clone(),
 5481                buffer_position,
 5482                input,
 5483                push_to_lsp_host_history,
 5484                cx,
 5485            )
 5486        });
 5487        Some(cx.spawn_in(window, async move |editor, cx| {
 5488            if let Some(transaction) = on_type_formatting.await? {
 5489                if push_to_client_history {
 5490                    buffer
 5491                        .update(cx, |buffer, _| {
 5492                            buffer.push_transaction(transaction, Instant::now());
 5493                            buffer.finalize_last_transaction();
 5494                        })
 5495                        .ok();
 5496                }
 5497                editor.update(cx, |editor, cx| {
 5498                    editor.refresh_document_highlights(cx);
 5499                })?;
 5500            }
 5501            Ok(())
 5502        }))
 5503    }
 5504
 5505    pub fn show_word_completions(
 5506        &mut self,
 5507        _: &ShowWordCompletions,
 5508        window: &mut Window,
 5509        cx: &mut Context<Self>,
 5510    ) {
 5511        self.open_or_update_completions_menu(
 5512            Some(CompletionsMenuSource::Words {
 5513                ignore_threshold: true,
 5514            }),
 5515            None,
 5516            false,
 5517            window,
 5518            cx,
 5519        );
 5520    }
 5521
 5522    pub fn show_completions(
 5523        &mut self,
 5524        _: &ShowCompletions,
 5525        window: &mut Window,
 5526        cx: &mut Context<Self>,
 5527    ) {
 5528        self.open_or_update_completions_menu(None, None, false, window, cx);
 5529    }
 5530
 5531    fn open_or_update_completions_menu(
 5532        &mut self,
 5533        requested_source: Option<CompletionsMenuSource>,
 5534        trigger: Option<String>,
 5535        trigger_in_words: bool,
 5536        window: &mut Window,
 5537        cx: &mut Context<Self>,
 5538    ) {
 5539        if self.pending_rename.is_some() {
 5540            return;
 5541        }
 5542
 5543        let completions_source = self
 5544            .context_menu
 5545            .borrow()
 5546            .as_ref()
 5547            .and_then(|menu| match menu {
 5548                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5549                CodeContextMenu::CodeActions(_) => None,
 5550            });
 5551
 5552        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5553
 5554        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5555        // inserted and selected. To handle that case, the start of the selection is used so that
 5556        // the menu starts with all choices.
 5557        let position = self
 5558            .selections
 5559            .newest_anchor()
 5560            .start
 5561            .bias_right(&multibuffer_snapshot);
 5562        if position.diff_base_anchor.is_some() {
 5563            return;
 5564        }
 5565        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5566        let Some(buffer) = buffer_position
 5567            .text_anchor
 5568            .buffer_id
 5569            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5570        else {
 5571            return;
 5572        };
 5573        let buffer_snapshot = buffer.read(cx).snapshot();
 5574
 5575        let menu_is_open = matches!(
 5576            self.context_menu.borrow().as_ref(),
 5577            Some(CodeContextMenu::Completions(_))
 5578        );
 5579
 5580        let language = buffer_snapshot
 5581            .language_at(buffer_position.text_anchor)
 5582            .map(|language| language.name());
 5583
 5584        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5585        let completion_settings = language_settings.completions.clone();
 5586
 5587        let show_completions_on_input = self
 5588            .show_completions_on_input_override
 5589            .unwrap_or(language_settings.show_completions_on_input);
 5590        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5591            return;
 5592        }
 5593
 5594        let query: Option<Arc<String>> =
 5595            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5596                .map(|query| query.into());
 5597
 5598        drop(multibuffer_snapshot);
 5599
 5600        // Hide the current completions menu when query is empty. Without this, cached
 5601        // completions from before the trigger char may be reused (#32774).
 5602        if query.is_none() && menu_is_open {
 5603            self.hide_context_menu(window, cx);
 5604        }
 5605
 5606        let mut ignore_word_threshold = false;
 5607        let provider = match requested_source {
 5608            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5609            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5610                ignore_word_threshold = ignore_threshold;
 5611                None
 5612            }
 5613            Some(CompletionsMenuSource::SnippetChoices)
 5614            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5615                log::error!("bug: SnippetChoices requested_source is not handled");
 5616                None
 5617            }
 5618        };
 5619
 5620        let sort_completions = provider
 5621            .as_ref()
 5622            .is_some_and(|provider| provider.sort_completions());
 5623
 5624        let filter_completions = provider
 5625            .as_ref()
 5626            .is_none_or(|provider| provider.filter_completions());
 5627
 5628        let was_snippets_only = matches!(
 5629            completions_source,
 5630            Some(CompletionsMenuSource::SnippetsOnly)
 5631        );
 5632
 5633        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5634            if filter_completions {
 5635                menu.filter(
 5636                    query.clone().unwrap_or_default(),
 5637                    buffer_position.text_anchor,
 5638                    &buffer,
 5639                    provider.clone(),
 5640                    window,
 5641                    cx,
 5642                );
 5643            }
 5644            // When `is_incomplete` is false, no need to re-query completions when the current query
 5645            // is a suffix of the initial query.
 5646            let was_complete = !menu.is_incomplete;
 5647            if was_complete && !was_snippets_only {
 5648                // If the new query is a suffix of the old query (typing more characters) and
 5649                // the previous result was complete, the existing completions can be filtered.
 5650                //
 5651                // Note that snippet completions are always complete.
 5652                let query_matches = match (&menu.initial_query, &query) {
 5653                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5654                    (None, _) => true,
 5655                    _ => false,
 5656                };
 5657                if query_matches {
 5658                    let position_matches = if menu.initial_position == position {
 5659                        true
 5660                    } else {
 5661                        let snapshot = self.buffer.read(cx).read(cx);
 5662                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5663                    };
 5664                    if position_matches {
 5665                        return;
 5666                    }
 5667                }
 5668            }
 5669        };
 5670
 5671        let Anchor {
 5672            excerpt_id: buffer_excerpt_id,
 5673            text_anchor: buffer_position,
 5674            ..
 5675        } = buffer_position;
 5676
 5677        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5678            buffer_snapshot.surrounding_word(buffer_position, None)
 5679        {
 5680            let word_to_exclude = buffer_snapshot
 5681                .text_for_range(word_range.clone())
 5682                .collect::<String>();
 5683            (
 5684                buffer_snapshot.anchor_before(word_range.start)
 5685                    ..buffer_snapshot.anchor_after(buffer_position),
 5686                Some(word_to_exclude),
 5687            )
 5688        } else {
 5689            (buffer_position..buffer_position, None)
 5690        };
 5691
 5692        let show_completion_documentation = buffer_snapshot
 5693            .settings_at(buffer_position, cx)
 5694            .show_completion_documentation;
 5695
 5696        // The document can be large, so stay in reasonable bounds when searching for words,
 5697        // otherwise completion pop-up might be slow to appear.
 5698        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5699        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5700        let min_word_search = buffer_snapshot.clip_point(
 5701            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5702            Bias::Left,
 5703        );
 5704        let max_word_search = buffer_snapshot.clip_point(
 5705            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5706            Bias::Right,
 5707        );
 5708        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5709            ..buffer_snapshot.point_to_offset(max_word_search);
 5710
 5711        let skip_digits = query
 5712            .as_ref()
 5713            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5714
 5715        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5716            trigger.as_ref().is_none_or(|trigger| {
 5717                provider.is_completion_trigger(
 5718                    &buffer,
 5719                    position.text_anchor,
 5720                    trigger,
 5721                    trigger_in_words,
 5722                    cx,
 5723                )
 5724            })
 5725        });
 5726
 5727        let provider_responses = if let Some(provider) = &provider
 5728            && load_provider_completions
 5729        {
 5730            let trigger_character =
 5731                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5732            let completion_context = CompletionContext {
 5733                trigger_kind: match &trigger_character {
 5734                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5735                    None => CompletionTriggerKind::INVOKED,
 5736                },
 5737                trigger_character,
 5738            };
 5739
 5740            provider.completions(
 5741                buffer_excerpt_id,
 5742                &buffer,
 5743                buffer_position,
 5744                completion_context,
 5745                window,
 5746                cx,
 5747            )
 5748        } else {
 5749            Task::ready(Ok(Vec::new()))
 5750        };
 5751
 5752        let load_word_completions = if !self.word_completions_enabled {
 5753            false
 5754        } else if requested_source
 5755            == Some(CompletionsMenuSource::Words {
 5756                ignore_threshold: true,
 5757            })
 5758        {
 5759            true
 5760        } else {
 5761            load_provider_completions
 5762                && completion_settings.words != WordsCompletionMode::Disabled
 5763                && (ignore_word_threshold || {
 5764                    let words_min_length = completion_settings.words_min_length;
 5765                    // check whether word has at least `words_min_length` characters
 5766                    let query_chars = query.iter().flat_map(|q| q.chars());
 5767                    query_chars.take(words_min_length).count() == words_min_length
 5768                })
 5769        };
 5770
 5771        let mut words = if load_word_completions {
 5772            cx.background_spawn({
 5773                let buffer_snapshot = buffer_snapshot.clone();
 5774                async move {
 5775                    buffer_snapshot.words_in_range(WordsQuery {
 5776                        fuzzy_contents: None,
 5777                        range: word_search_range,
 5778                        skip_digits,
 5779                    })
 5780                }
 5781            })
 5782        } else {
 5783            Task::ready(BTreeMap::default())
 5784        };
 5785
 5786        let snippets = if let Some(provider) = &provider
 5787            && provider.show_snippets()
 5788            && let Some(project) = self.project()
 5789        {
 5790            let char_classifier = buffer_snapshot
 5791                .char_classifier_at(buffer_position)
 5792                .scope_context(Some(CharScopeContext::Completion));
 5793            project.update(cx, |project, cx| {
 5794                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5795            })
 5796        } else {
 5797            Task::ready(Ok(CompletionResponse {
 5798                completions: Vec::new(),
 5799                display_options: Default::default(),
 5800                is_incomplete: false,
 5801            }))
 5802        };
 5803
 5804        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5805
 5806        let id = post_inc(&mut self.next_completion_id);
 5807        let task = cx.spawn_in(window, async move |editor, cx| {
 5808            let Ok(()) = editor.update(cx, |this, _| {
 5809                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5810            }) else {
 5811                return;
 5812            };
 5813
 5814            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5815            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5816            let mut completions = Vec::new();
 5817            let mut is_incomplete = false;
 5818            let mut display_options: Option<CompletionDisplayOptions> = None;
 5819            if let Some(provider_responses) = provider_responses.await.log_err()
 5820                && !provider_responses.is_empty()
 5821            {
 5822                for response in provider_responses {
 5823                    completions.extend(response.completions);
 5824                    is_incomplete = is_incomplete || response.is_incomplete;
 5825                    match display_options.as_mut() {
 5826                        None => {
 5827                            display_options = Some(response.display_options);
 5828                        }
 5829                        Some(options) => options.merge(&response.display_options),
 5830                    }
 5831                }
 5832                if completion_settings.words == WordsCompletionMode::Fallback {
 5833                    words = Task::ready(BTreeMap::default());
 5834                }
 5835            }
 5836            let display_options = display_options.unwrap_or_default();
 5837
 5838            let mut words = words.await;
 5839            if let Some(word_to_exclude) = &word_to_exclude {
 5840                words.remove(word_to_exclude);
 5841            }
 5842            for lsp_completion in &completions {
 5843                words.remove(&lsp_completion.new_text);
 5844            }
 5845            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5846                replace_range: word_replace_range.clone(),
 5847                new_text: word.clone(),
 5848                label: CodeLabel::plain(word, None),
 5849                match_start: None,
 5850                snippet_deduplication_key: None,
 5851                icon_path: None,
 5852                documentation: None,
 5853                source: CompletionSource::BufferWord {
 5854                    word_range,
 5855                    resolved: false,
 5856                },
 5857                insert_text_mode: Some(InsertTextMode::AS_IS),
 5858                confirm: None,
 5859            }));
 5860
 5861            completions.extend(
 5862                snippets
 5863                    .await
 5864                    .into_iter()
 5865                    .flat_map(|response| response.completions),
 5866            );
 5867
 5868            let menu = if completions.is_empty() {
 5869                None
 5870            } else {
 5871                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5872                    let languages = editor
 5873                        .workspace
 5874                        .as_ref()
 5875                        .and_then(|(workspace, _)| workspace.upgrade())
 5876                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5877                    let menu = CompletionsMenu::new(
 5878                        id,
 5879                        requested_source.unwrap_or(if load_provider_completions {
 5880                            CompletionsMenuSource::Normal
 5881                        } else {
 5882                            CompletionsMenuSource::SnippetsOnly
 5883                        }),
 5884                        sort_completions,
 5885                        show_completion_documentation,
 5886                        position,
 5887                        query.clone(),
 5888                        is_incomplete,
 5889                        buffer.clone(),
 5890                        completions.into(),
 5891                        editor
 5892                            .context_menu()
 5893                            .borrow_mut()
 5894                            .as_ref()
 5895                            .map(|menu| menu.primary_scroll_handle()),
 5896                        display_options,
 5897                        snippet_sort_order,
 5898                        languages,
 5899                        language,
 5900                        cx,
 5901                    );
 5902
 5903                    let query = if filter_completions { query } else { None };
 5904                    let matches_task = menu.do_async_filtering(
 5905                        query.unwrap_or_default(),
 5906                        buffer_position,
 5907                        &buffer,
 5908                        cx,
 5909                    );
 5910                    (menu, matches_task)
 5911                }) else {
 5912                    return;
 5913                };
 5914
 5915                let matches = matches_task.await;
 5916
 5917                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5918                    // Newer menu already set, so exit.
 5919                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5920                        editor.context_menu.borrow().as_ref()
 5921                        && prev_menu.id > id
 5922                    {
 5923                        return;
 5924                    };
 5925
 5926                    // Only valid to take prev_menu because either the new menu is immediately set
 5927                    // below, or the menu is hidden.
 5928                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5929                        editor.context_menu.borrow_mut().take()
 5930                    {
 5931                        let position_matches =
 5932                            if prev_menu.initial_position == menu.initial_position {
 5933                                true
 5934                            } else {
 5935                                let snapshot = editor.buffer.read(cx).read(cx);
 5936                                prev_menu.initial_position.to_offset(&snapshot)
 5937                                    == menu.initial_position.to_offset(&snapshot)
 5938                            };
 5939                        if position_matches {
 5940                            // Preserve markdown cache before `set_filter_results` because it will
 5941                            // try to populate the documentation cache.
 5942                            menu.preserve_markdown_cache(prev_menu);
 5943                        }
 5944                    };
 5945
 5946                    menu.set_filter_results(matches, provider, window, cx);
 5947                }) else {
 5948                    return;
 5949                };
 5950
 5951                menu.visible().then_some(menu)
 5952            };
 5953
 5954            editor
 5955                .update_in(cx, |editor, window, cx| {
 5956                    if editor.focus_handle.is_focused(window)
 5957                        && let Some(menu) = menu
 5958                    {
 5959                        *editor.context_menu.borrow_mut() =
 5960                            Some(CodeContextMenu::Completions(menu));
 5961
 5962                        crate::hover_popover::hide_hover(editor, cx);
 5963                        if editor.show_edit_predictions_in_menu() {
 5964                            editor.update_visible_edit_prediction(window, cx);
 5965                        } else {
 5966                            editor.discard_edit_prediction(false, cx);
 5967                        }
 5968
 5969                        cx.notify();
 5970                        return;
 5971                    }
 5972
 5973                    if editor.completion_tasks.len() <= 1 {
 5974                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5975                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5976                        // If it was already hidden and we don't show edit predictions in the menu,
 5977                        // we should also show the edit prediction when available.
 5978                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5979                            editor.update_visible_edit_prediction(window, cx);
 5980                        }
 5981                    }
 5982                })
 5983                .ok();
 5984        });
 5985
 5986        self.completion_tasks.push((id, task));
 5987    }
 5988
 5989    #[cfg(feature = "test-support")]
 5990    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5991        let menu = self.context_menu.borrow();
 5992        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5993            let completions = menu.completions.borrow();
 5994            Some(completions.to_vec())
 5995        } else {
 5996            None
 5997        }
 5998    }
 5999
 6000    pub fn with_completions_menu_matching_id<R>(
 6001        &self,
 6002        id: CompletionId,
 6003        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6004    ) -> R {
 6005        let mut context_menu = self.context_menu.borrow_mut();
 6006        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6007            return f(None);
 6008        };
 6009        if completions_menu.id != id {
 6010            return f(None);
 6011        }
 6012        f(Some(completions_menu))
 6013    }
 6014
 6015    pub fn confirm_completion(
 6016        &mut self,
 6017        action: &ConfirmCompletion,
 6018        window: &mut Window,
 6019        cx: &mut Context<Self>,
 6020    ) -> Option<Task<Result<()>>> {
 6021        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6022        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6023    }
 6024
 6025    pub fn confirm_completion_insert(
 6026        &mut self,
 6027        _: &ConfirmCompletionInsert,
 6028        window: &mut Window,
 6029        cx: &mut Context<Self>,
 6030    ) -> Option<Task<Result<()>>> {
 6031        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6032        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6033    }
 6034
 6035    pub fn confirm_completion_replace(
 6036        &mut self,
 6037        _: &ConfirmCompletionReplace,
 6038        window: &mut Window,
 6039        cx: &mut Context<Self>,
 6040    ) -> Option<Task<Result<()>>> {
 6041        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6042        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6043    }
 6044
 6045    pub fn compose_completion(
 6046        &mut self,
 6047        action: &ComposeCompletion,
 6048        window: &mut Window,
 6049        cx: &mut Context<Self>,
 6050    ) -> Option<Task<Result<()>>> {
 6051        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6052        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6053    }
 6054
 6055    fn do_completion(
 6056        &mut self,
 6057        item_ix: Option<usize>,
 6058        intent: CompletionIntent,
 6059        window: &mut Window,
 6060        cx: &mut Context<Editor>,
 6061    ) -> Option<Task<Result<()>>> {
 6062        use language::ToOffset as _;
 6063
 6064        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6065        else {
 6066            return None;
 6067        };
 6068
 6069        let candidate_id = {
 6070            let entries = completions_menu.entries.borrow();
 6071            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6072            if self.show_edit_predictions_in_menu() {
 6073                self.discard_edit_prediction(true, cx);
 6074            }
 6075            mat.candidate_id
 6076        };
 6077
 6078        let completion = completions_menu
 6079            .completions
 6080            .borrow()
 6081            .get(candidate_id)?
 6082            .clone();
 6083        cx.stop_propagation();
 6084
 6085        let buffer_handle = completions_menu.buffer.clone();
 6086
 6087        let CompletionEdit {
 6088            new_text,
 6089            snippet,
 6090            replace_range,
 6091        } = process_completion_for_edit(
 6092            &completion,
 6093            intent,
 6094            &buffer_handle,
 6095            &completions_menu.initial_position.text_anchor,
 6096            cx,
 6097        );
 6098
 6099        let buffer = buffer_handle.read(cx);
 6100        let snapshot = self.buffer.read(cx).snapshot(cx);
 6101        let newest_anchor = self.selections.newest_anchor();
 6102        let replace_range_multibuffer = {
 6103            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6104            excerpt.map_range_from_buffer(replace_range.clone())
 6105        };
 6106        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6107            return None;
 6108        }
 6109
 6110        let old_text = buffer
 6111            .text_for_range(replace_range.clone())
 6112            .collect::<String>();
 6113        let lookbehind = newest_anchor
 6114            .start
 6115            .text_anchor
 6116            .to_offset(buffer)
 6117            .saturating_sub(replace_range.start.0);
 6118        let lookahead = replace_range
 6119            .end
 6120            .0
 6121            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6122        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6123        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6124
 6125        let selections = self
 6126            .selections
 6127            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6128        let mut ranges = Vec::new();
 6129        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6130
 6131        for selection in &selections {
 6132            let range = if selection.id == newest_anchor.id {
 6133                replace_range_multibuffer.clone()
 6134            } else {
 6135                let mut range = selection.range();
 6136
 6137                // if prefix is present, don't duplicate it
 6138                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6139                    range.start = range.start.saturating_sub_usize(lookbehind);
 6140
 6141                    // if suffix is also present, mimic the newest cursor and replace it
 6142                    if selection.id != newest_anchor.id
 6143                        && snapshot.contains_str_at(range.end, suffix)
 6144                    {
 6145                        range.end += lookahead;
 6146                    }
 6147                }
 6148                range
 6149            };
 6150
 6151            ranges.push(range.clone());
 6152
 6153            if !self.linked_edit_ranges.is_empty() {
 6154                let start_anchor = snapshot.anchor_before(range.start);
 6155                let end_anchor = snapshot.anchor_after(range.end);
 6156                if let Some(ranges) = self
 6157                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6158                {
 6159                    for (buffer, edits) in ranges {
 6160                        linked_edits
 6161                            .entry(buffer.clone())
 6162                            .or_default()
 6163                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6164                    }
 6165                }
 6166            }
 6167        }
 6168
 6169        let common_prefix_len = old_text
 6170            .chars()
 6171            .zip(new_text.chars())
 6172            .take_while(|(a, b)| a == b)
 6173            .map(|(a, _)| a.len_utf8())
 6174            .sum::<usize>();
 6175
 6176        cx.emit(EditorEvent::InputHandled {
 6177            utf16_range_to_replace: None,
 6178            text: new_text[common_prefix_len..].into(),
 6179        });
 6180
 6181        self.transact(window, cx, |editor, window, cx| {
 6182            if let Some(mut snippet) = snippet {
 6183                snippet.text = new_text.to_string();
 6184                editor
 6185                    .insert_snippet(&ranges, snippet, window, cx)
 6186                    .log_err();
 6187            } else {
 6188                editor.buffer.update(cx, |multi_buffer, cx| {
 6189                    let auto_indent = match completion.insert_text_mode {
 6190                        Some(InsertTextMode::AS_IS) => None,
 6191                        _ => editor.autoindent_mode.clone(),
 6192                    };
 6193                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6194                    multi_buffer.edit(edits, auto_indent, cx);
 6195                });
 6196            }
 6197            for (buffer, edits) in linked_edits {
 6198                buffer.update(cx, |buffer, cx| {
 6199                    let snapshot = buffer.snapshot();
 6200                    let edits = edits
 6201                        .into_iter()
 6202                        .map(|(range, text)| {
 6203                            use text::ToPoint as TP;
 6204                            let end_point = TP::to_point(&range.end, &snapshot);
 6205                            let start_point = TP::to_point(&range.start, &snapshot);
 6206                            (start_point..end_point, text)
 6207                        })
 6208                        .sorted_by_key(|(range, _)| range.start);
 6209                    buffer.edit(edits, None, cx);
 6210                })
 6211            }
 6212
 6213            editor.refresh_edit_prediction(true, false, window, cx);
 6214        });
 6215        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6216
 6217        let show_new_completions_on_confirm = completion
 6218            .confirm
 6219            .as_ref()
 6220            .is_some_and(|confirm| confirm(intent, window, cx));
 6221        if show_new_completions_on_confirm {
 6222            self.open_or_update_completions_menu(None, None, false, window, cx);
 6223        }
 6224
 6225        let provider = self.completion_provider.as_ref()?;
 6226
 6227        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6228        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6229            let CompletionSource::Lsp {
 6230                lsp_completion,
 6231                server_id,
 6232                ..
 6233            } = &completion.source
 6234            else {
 6235                return None;
 6236            };
 6237            let lsp_command = lsp_completion.command.as_ref()?;
 6238            let available_commands = lsp_store
 6239                .read(cx)
 6240                .lsp_server_capabilities
 6241                .get(server_id)
 6242                .and_then(|server_capabilities| {
 6243                    server_capabilities
 6244                        .execute_command_provider
 6245                        .as_ref()
 6246                        .map(|options| options.commands.as_slice())
 6247                })?;
 6248            if available_commands.contains(&lsp_command.command) {
 6249                Some(CodeAction {
 6250                    server_id: *server_id,
 6251                    range: language::Anchor::MIN..language::Anchor::MIN,
 6252                    lsp_action: LspAction::Command(lsp_command.clone()),
 6253                    resolved: false,
 6254                })
 6255            } else {
 6256                None
 6257            }
 6258        });
 6259
 6260        drop(completion);
 6261        let apply_edits = provider.apply_additional_edits_for_completion(
 6262            buffer_handle.clone(),
 6263            completions_menu.completions.clone(),
 6264            candidate_id,
 6265            true,
 6266            cx,
 6267        );
 6268
 6269        let editor_settings = EditorSettings::get_global(cx);
 6270        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6271            // After the code completion is finished, users often want to know what signatures are needed.
 6272            // so we should automatically call signature_help
 6273            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6274        }
 6275
 6276        Some(cx.spawn_in(window, async move |editor, cx| {
 6277            apply_edits.await?;
 6278
 6279            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6280                let title = command.lsp_action.title().to_owned();
 6281                let project_transaction = lsp_store
 6282                    .update(cx, |lsp_store, cx| {
 6283                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6284                    })?
 6285                    .await
 6286                    .context("applying post-completion command")?;
 6287                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6288                    Self::open_project_transaction(
 6289                        &editor,
 6290                        workspace.downgrade(),
 6291                        project_transaction,
 6292                        title,
 6293                        cx,
 6294                    )
 6295                    .await?;
 6296                }
 6297            }
 6298
 6299            Ok(())
 6300        }))
 6301    }
 6302
 6303    pub fn toggle_code_actions(
 6304        &mut self,
 6305        action: &ToggleCodeActions,
 6306        window: &mut Window,
 6307        cx: &mut Context<Self>,
 6308    ) {
 6309        let quick_launch = action.quick_launch;
 6310        let mut context_menu = self.context_menu.borrow_mut();
 6311        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6312            if code_actions.deployed_from == action.deployed_from {
 6313                // Toggle if we're selecting the same one
 6314                *context_menu = None;
 6315                cx.notify();
 6316                return;
 6317            } else {
 6318                // Otherwise, clear it and start a new one
 6319                *context_menu = None;
 6320                cx.notify();
 6321            }
 6322        }
 6323        drop(context_menu);
 6324        let snapshot = self.snapshot(window, cx);
 6325        let deployed_from = action.deployed_from.clone();
 6326        let action = action.clone();
 6327        self.completion_tasks.clear();
 6328        self.discard_edit_prediction(false, cx);
 6329
 6330        let multibuffer_point = match &action.deployed_from {
 6331            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6332                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6333            }
 6334            _ => self
 6335                .selections
 6336                .newest::<Point>(&snapshot.display_snapshot)
 6337                .head(),
 6338        };
 6339        let Some((buffer, buffer_row)) = snapshot
 6340            .buffer_snapshot()
 6341            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6342            .and_then(|(buffer_snapshot, range)| {
 6343                self.buffer()
 6344                    .read(cx)
 6345                    .buffer(buffer_snapshot.remote_id())
 6346                    .map(|buffer| (buffer, range.start.row))
 6347            })
 6348        else {
 6349            return;
 6350        };
 6351        let buffer_id = buffer.read(cx).remote_id();
 6352        let tasks = self
 6353            .tasks
 6354            .get(&(buffer_id, buffer_row))
 6355            .map(|t| Arc::new(t.to_owned()));
 6356
 6357        if !self.focus_handle.is_focused(window) {
 6358            return;
 6359        }
 6360        let project = self.project.clone();
 6361
 6362        let code_actions_task = match deployed_from {
 6363            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6364            _ => self.code_actions(buffer_row, window, cx),
 6365        };
 6366
 6367        let runnable_task = match deployed_from {
 6368            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6369            _ => {
 6370                let mut task_context_task = Task::ready(None);
 6371                if let Some(tasks) = &tasks
 6372                    && let Some(project) = project
 6373                {
 6374                    task_context_task =
 6375                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6376                }
 6377
 6378                cx.spawn_in(window, {
 6379                    let buffer = buffer.clone();
 6380                    async move |editor, cx| {
 6381                        let task_context = task_context_task.await;
 6382
 6383                        let resolved_tasks =
 6384                            tasks
 6385                                .zip(task_context.clone())
 6386                                .map(|(tasks, task_context)| ResolvedTasks {
 6387                                    templates: tasks.resolve(&task_context).collect(),
 6388                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6389                                        multibuffer_point.row,
 6390                                        tasks.column,
 6391                                    )),
 6392                                });
 6393                        let debug_scenarios = editor
 6394                            .update(cx, |editor, cx| {
 6395                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6396                            })?
 6397                            .await;
 6398                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6399                    }
 6400                })
 6401            }
 6402        };
 6403
 6404        cx.spawn_in(window, async move |editor, cx| {
 6405            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6406            let code_actions = code_actions_task.await;
 6407            let spawn_straight_away = quick_launch
 6408                && resolved_tasks
 6409                    .as_ref()
 6410                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6411                && code_actions
 6412                    .as_ref()
 6413                    .is_none_or(|actions| actions.is_empty())
 6414                && debug_scenarios.is_empty();
 6415
 6416            editor.update_in(cx, |editor, window, cx| {
 6417                crate::hover_popover::hide_hover(editor, cx);
 6418                let actions = CodeActionContents::new(
 6419                    resolved_tasks,
 6420                    code_actions,
 6421                    debug_scenarios,
 6422                    task_context.unwrap_or_default(),
 6423                );
 6424
 6425                // Don't show the menu if there are no actions available
 6426                if actions.is_empty() {
 6427                    cx.notify();
 6428                    return Task::ready(Ok(()));
 6429                }
 6430
 6431                *editor.context_menu.borrow_mut() =
 6432                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6433                        buffer,
 6434                        actions,
 6435                        selected_item: Default::default(),
 6436                        scroll_handle: UniformListScrollHandle::default(),
 6437                        deployed_from,
 6438                    }));
 6439                cx.notify();
 6440                if spawn_straight_away
 6441                    && let Some(task) = editor.confirm_code_action(
 6442                        &ConfirmCodeAction { item_ix: Some(0) },
 6443                        window,
 6444                        cx,
 6445                    )
 6446                {
 6447                    return task;
 6448                }
 6449
 6450                Task::ready(Ok(()))
 6451            })
 6452        })
 6453        .detach_and_log_err(cx);
 6454    }
 6455
 6456    fn debug_scenarios(
 6457        &mut self,
 6458        resolved_tasks: &Option<ResolvedTasks>,
 6459        buffer: &Entity<Buffer>,
 6460        cx: &mut App,
 6461    ) -> Task<Vec<task::DebugScenario>> {
 6462        maybe!({
 6463            let project = self.project()?;
 6464            let dap_store = project.read(cx).dap_store();
 6465            let mut scenarios = vec![];
 6466            let resolved_tasks = resolved_tasks.as_ref()?;
 6467            let buffer = buffer.read(cx);
 6468            let language = buffer.language()?;
 6469            let file = buffer.file();
 6470            let debug_adapter = language_settings(language.name().into(), file, cx)
 6471                .debuggers
 6472                .first()
 6473                .map(SharedString::from)
 6474                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6475
 6476            dap_store.update(cx, |dap_store, cx| {
 6477                for (_, task) in &resolved_tasks.templates {
 6478                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6479                        task.original_task().clone(),
 6480                        debug_adapter.clone().into(),
 6481                        task.display_label().to_owned().into(),
 6482                        cx,
 6483                    );
 6484                    scenarios.push(maybe_scenario);
 6485                }
 6486            });
 6487            Some(cx.background_spawn(async move {
 6488                futures::future::join_all(scenarios)
 6489                    .await
 6490                    .into_iter()
 6491                    .flatten()
 6492                    .collect::<Vec<_>>()
 6493            }))
 6494        })
 6495        .unwrap_or_else(|| Task::ready(vec![]))
 6496    }
 6497
 6498    fn code_actions(
 6499        &mut self,
 6500        buffer_row: u32,
 6501        window: &mut Window,
 6502        cx: &mut Context<Self>,
 6503    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6504        let mut task = self.code_actions_task.take();
 6505        cx.spawn_in(window, async move |editor, cx| {
 6506            while let Some(prev_task) = task {
 6507                prev_task.await.log_err();
 6508                task = editor
 6509                    .update(cx, |this, _| this.code_actions_task.take())
 6510                    .ok()?;
 6511            }
 6512
 6513            editor
 6514                .update(cx, |editor, cx| {
 6515                    editor
 6516                        .available_code_actions
 6517                        .clone()
 6518                        .and_then(|(location, code_actions)| {
 6519                            let snapshot = location.buffer.read(cx).snapshot();
 6520                            let point_range = location.range.to_point(&snapshot);
 6521                            let point_range = point_range.start.row..=point_range.end.row;
 6522                            if point_range.contains(&buffer_row) {
 6523                                Some(code_actions)
 6524                            } else {
 6525                                None
 6526                            }
 6527                        })
 6528                })
 6529                .ok()
 6530                .flatten()
 6531        })
 6532    }
 6533
 6534    pub fn confirm_code_action(
 6535        &mut self,
 6536        action: &ConfirmCodeAction,
 6537        window: &mut Window,
 6538        cx: &mut Context<Self>,
 6539    ) -> Option<Task<Result<()>>> {
 6540        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6541
 6542        let actions_menu =
 6543            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6544                menu
 6545            } else {
 6546                return None;
 6547            };
 6548
 6549        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6550        let action = actions_menu.actions.get(action_ix)?;
 6551        let title = action.label();
 6552        let buffer = actions_menu.buffer;
 6553        let workspace = self.workspace()?;
 6554
 6555        match action {
 6556            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6557                workspace.update(cx, |workspace, cx| {
 6558                    workspace.schedule_resolved_task(
 6559                        task_source_kind,
 6560                        resolved_task,
 6561                        false,
 6562                        window,
 6563                        cx,
 6564                    );
 6565
 6566                    Some(Task::ready(Ok(())))
 6567                })
 6568            }
 6569            CodeActionsItem::CodeAction {
 6570                excerpt_id,
 6571                action,
 6572                provider,
 6573            } => {
 6574                let apply_code_action =
 6575                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6576                let workspace = workspace.downgrade();
 6577                Some(cx.spawn_in(window, async move |editor, cx| {
 6578                    let project_transaction = apply_code_action.await?;
 6579                    Self::open_project_transaction(
 6580                        &editor,
 6581                        workspace,
 6582                        project_transaction,
 6583                        title,
 6584                        cx,
 6585                    )
 6586                    .await
 6587                }))
 6588            }
 6589            CodeActionsItem::DebugScenario(scenario) => {
 6590                let context = actions_menu.actions.context;
 6591
 6592                workspace.update(cx, |workspace, cx| {
 6593                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6594                    workspace.start_debug_session(
 6595                        scenario,
 6596                        context,
 6597                        Some(buffer),
 6598                        None,
 6599                        window,
 6600                        cx,
 6601                    );
 6602                });
 6603                Some(Task::ready(Ok(())))
 6604            }
 6605        }
 6606    }
 6607
 6608    pub async fn open_project_transaction(
 6609        editor: &WeakEntity<Editor>,
 6610        workspace: WeakEntity<Workspace>,
 6611        transaction: ProjectTransaction,
 6612        title: String,
 6613        cx: &mut AsyncWindowContext,
 6614    ) -> Result<()> {
 6615        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6616        cx.update(|_, cx| {
 6617            entries.sort_unstable_by_key(|(buffer, _)| {
 6618                buffer.read(cx).file().map(|f| f.path().clone())
 6619            });
 6620        })?;
 6621        if entries.is_empty() {
 6622            return Ok(());
 6623        }
 6624
 6625        // If the project transaction's edits are all contained within this editor, then
 6626        // avoid opening a new editor to display them.
 6627
 6628        if let [(buffer, transaction)] = &*entries {
 6629            let excerpt = editor.update(cx, |editor, cx| {
 6630                editor
 6631                    .buffer()
 6632                    .read(cx)
 6633                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6634            })?;
 6635            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6636                && excerpted_buffer == *buffer
 6637            {
 6638                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6639                    let excerpt_range = excerpt_range.to_offset(buffer);
 6640                    buffer
 6641                        .edited_ranges_for_transaction::<usize>(transaction)
 6642                        .all(|range| {
 6643                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6644                        })
 6645                })?;
 6646
 6647                if all_edits_within_excerpt {
 6648                    return Ok(());
 6649                }
 6650            }
 6651        }
 6652
 6653        let mut ranges_to_highlight = Vec::new();
 6654        let excerpt_buffer = cx.new(|cx| {
 6655            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6656            for (buffer_handle, transaction) in &entries {
 6657                let edited_ranges = buffer_handle
 6658                    .read(cx)
 6659                    .edited_ranges_for_transaction::<Point>(transaction)
 6660                    .collect::<Vec<_>>();
 6661                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6662                    PathKey::for_buffer(buffer_handle, cx),
 6663                    buffer_handle.clone(),
 6664                    edited_ranges,
 6665                    multibuffer_context_lines(cx),
 6666                    cx,
 6667                );
 6668
 6669                ranges_to_highlight.extend(ranges);
 6670            }
 6671            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6672            multibuffer
 6673        })?;
 6674
 6675        workspace.update_in(cx, |workspace, window, cx| {
 6676            let project = workspace.project().clone();
 6677            let editor =
 6678                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6679            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6680            editor.update(cx, |editor, cx| {
 6681                editor.highlight_background::<Self>(
 6682                    &ranges_to_highlight,
 6683                    |_, theme| theme.colors().editor_highlighted_line_background,
 6684                    cx,
 6685                );
 6686            });
 6687        })?;
 6688
 6689        Ok(())
 6690    }
 6691
 6692    pub fn clear_code_action_providers(&mut self) {
 6693        self.code_action_providers.clear();
 6694        self.available_code_actions.take();
 6695    }
 6696
 6697    pub fn add_code_action_provider(
 6698        &mut self,
 6699        provider: Rc<dyn CodeActionProvider>,
 6700        window: &mut Window,
 6701        cx: &mut Context<Self>,
 6702    ) {
 6703        if self
 6704            .code_action_providers
 6705            .iter()
 6706            .any(|existing_provider| existing_provider.id() == provider.id())
 6707        {
 6708            return;
 6709        }
 6710
 6711        self.code_action_providers.push(provider);
 6712        self.refresh_code_actions(window, cx);
 6713    }
 6714
 6715    pub fn remove_code_action_provider(
 6716        &mut self,
 6717        id: Arc<str>,
 6718        window: &mut Window,
 6719        cx: &mut Context<Self>,
 6720    ) {
 6721        self.code_action_providers
 6722            .retain(|provider| provider.id() != id);
 6723        self.refresh_code_actions(window, cx);
 6724    }
 6725
 6726    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6727        !self.code_action_providers.is_empty()
 6728            && EditorSettings::get_global(cx).toolbar.code_actions
 6729    }
 6730
 6731    pub fn has_available_code_actions(&self) -> bool {
 6732        self.available_code_actions
 6733            .as_ref()
 6734            .is_some_and(|(_, actions)| !actions.is_empty())
 6735    }
 6736
 6737    fn render_inline_code_actions(
 6738        &self,
 6739        icon_size: ui::IconSize,
 6740        display_row: DisplayRow,
 6741        is_active: bool,
 6742        cx: &mut Context<Self>,
 6743    ) -> AnyElement {
 6744        let show_tooltip = !self.context_menu_visible();
 6745        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6746            .icon_size(icon_size)
 6747            .shape(ui::IconButtonShape::Square)
 6748            .icon_color(ui::Color::Hidden)
 6749            .toggle_state(is_active)
 6750            .when(show_tooltip, |this| {
 6751                this.tooltip({
 6752                    let focus_handle = self.focus_handle.clone();
 6753                    move |_window, cx| {
 6754                        Tooltip::for_action_in(
 6755                            "Toggle Code Actions",
 6756                            &ToggleCodeActions {
 6757                                deployed_from: None,
 6758                                quick_launch: false,
 6759                            },
 6760                            &focus_handle,
 6761                            cx,
 6762                        )
 6763                    }
 6764                })
 6765            })
 6766            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6767                window.focus(&editor.focus_handle(cx));
 6768                editor.toggle_code_actions(
 6769                    &crate::actions::ToggleCodeActions {
 6770                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6771                            display_row,
 6772                        )),
 6773                        quick_launch: false,
 6774                    },
 6775                    window,
 6776                    cx,
 6777                );
 6778            }))
 6779            .into_any_element()
 6780    }
 6781
 6782    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6783        &self.context_menu
 6784    }
 6785
 6786    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6787        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6788            cx.background_executor()
 6789                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6790                .await;
 6791
 6792            let (start_buffer, start, _, end, newest_selection) = this
 6793                .update(cx, |this, cx| {
 6794                    let newest_selection = this.selections.newest_anchor().clone();
 6795                    if newest_selection.head().diff_base_anchor.is_some() {
 6796                        return None;
 6797                    }
 6798                    let display_snapshot = this.display_snapshot(cx);
 6799                    let newest_selection_adjusted =
 6800                        this.selections.newest_adjusted(&display_snapshot);
 6801                    let buffer = this.buffer.read(cx);
 6802
 6803                    let (start_buffer, start) =
 6804                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6805                    let (end_buffer, end) =
 6806                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6807
 6808                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6809                })?
 6810                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6811                .context(
 6812                    "Expected selection to lie in a single buffer when refreshing code actions",
 6813                )?;
 6814            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6815                let providers = this.code_action_providers.clone();
 6816                let tasks = this
 6817                    .code_action_providers
 6818                    .iter()
 6819                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6820                    .collect::<Vec<_>>();
 6821                (providers, tasks)
 6822            })?;
 6823
 6824            let mut actions = Vec::new();
 6825            for (provider, provider_actions) in
 6826                providers.into_iter().zip(future::join_all(tasks).await)
 6827            {
 6828                if let Some(provider_actions) = provider_actions.log_err() {
 6829                    actions.extend(provider_actions.into_iter().map(|action| {
 6830                        AvailableCodeAction {
 6831                            excerpt_id: newest_selection.start.excerpt_id,
 6832                            action,
 6833                            provider: provider.clone(),
 6834                        }
 6835                    }));
 6836                }
 6837            }
 6838
 6839            this.update(cx, |this, cx| {
 6840                this.available_code_actions = if actions.is_empty() {
 6841                    None
 6842                } else {
 6843                    Some((
 6844                        Location {
 6845                            buffer: start_buffer,
 6846                            range: start..end,
 6847                        },
 6848                        actions.into(),
 6849                    ))
 6850                };
 6851                cx.notify();
 6852            })
 6853        }));
 6854    }
 6855
 6856    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6857        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6858            self.show_git_blame_inline = false;
 6859
 6860            self.show_git_blame_inline_delay_task =
 6861                Some(cx.spawn_in(window, async move |this, cx| {
 6862                    cx.background_executor().timer(delay).await;
 6863
 6864                    this.update(cx, |this, cx| {
 6865                        this.show_git_blame_inline = true;
 6866                        cx.notify();
 6867                    })
 6868                    .log_err();
 6869                }));
 6870        }
 6871    }
 6872
 6873    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6874        let snapshot = self.snapshot(window, cx);
 6875        let cursor = self
 6876            .selections
 6877            .newest::<Point>(&snapshot.display_snapshot)
 6878            .head();
 6879        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6880        else {
 6881            return;
 6882        };
 6883
 6884        if self.blame.is_none() {
 6885            self.start_git_blame(true, window, cx);
 6886        }
 6887        let Some(blame) = self.blame.as_ref() else {
 6888            return;
 6889        };
 6890
 6891        let row_info = RowInfo {
 6892            buffer_id: Some(buffer.remote_id()),
 6893            buffer_row: Some(point.row),
 6894            ..Default::default()
 6895        };
 6896        let Some((buffer, blame_entry)) = blame
 6897            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6898            .flatten()
 6899        else {
 6900            return;
 6901        };
 6902
 6903        let anchor = self.selections.newest_anchor().head();
 6904        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 6905        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6906            self.show_blame_popover(
 6907                buffer,
 6908                &blame_entry,
 6909                position + last_bounds.origin,
 6910                true,
 6911                cx,
 6912            );
 6913        };
 6914    }
 6915
 6916    fn show_blame_popover(
 6917        &mut self,
 6918        buffer: BufferId,
 6919        blame_entry: &BlameEntry,
 6920        position: gpui::Point<Pixels>,
 6921        ignore_timeout: bool,
 6922        cx: &mut Context<Self>,
 6923    ) {
 6924        if let Some(state) = &mut self.inline_blame_popover {
 6925            state.hide_task.take();
 6926        } else {
 6927            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6928            let blame_entry = blame_entry.clone();
 6929            let show_task = cx.spawn(async move |editor, cx| {
 6930                if !ignore_timeout {
 6931                    cx.background_executor()
 6932                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6933                        .await;
 6934                }
 6935                editor
 6936                    .update(cx, |editor, cx| {
 6937                        editor.inline_blame_popover_show_task.take();
 6938                        let Some(blame) = editor.blame.as_ref() else {
 6939                            return;
 6940                        };
 6941                        let blame = blame.read(cx);
 6942                        let details = blame.details_for_entry(buffer, &blame_entry);
 6943                        let markdown = cx.new(|cx| {
 6944                            Markdown::new(
 6945                                details
 6946                                    .as_ref()
 6947                                    .map(|message| message.message.clone())
 6948                                    .unwrap_or_default(),
 6949                                None,
 6950                                None,
 6951                                cx,
 6952                            )
 6953                        });
 6954                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6955                            position,
 6956                            hide_task: None,
 6957                            popover_bounds: None,
 6958                            popover_state: InlineBlamePopoverState {
 6959                                scroll_handle: ScrollHandle::new(),
 6960                                commit_message: details,
 6961                                markdown,
 6962                            },
 6963                            keyboard_grace: ignore_timeout,
 6964                        });
 6965                        cx.notify();
 6966                    })
 6967                    .ok();
 6968            });
 6969            self.inline_blame_popover_show_task = Some(show_task);
 6970        }
 6971    }
 6972
 6973    pub fn has_mouse_context_menu(&self) -> bool {
 6974        self.mouse_context_menu.is_some()
 6975    }
 6976
 6977    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6978        self.inline_blame_popover_show_task.take();
 6979        if let Some(state) = &mut self.inline_blame_popover {
 6980            let hide_task = cx.spawn(async move |editor, cx| {
 6981                if !ignore_timeout {
 6982                    cx.background_executor()
 6983                        .timer(std::time::Duration::from_millis(100))
 6984                        .await;
 6985                }
 6986                editor
 6987                    .update(cx, |editor, cx| {
 6988                        editor.inline_blame_popover.take();
 6989                        cx.notify();
 6990                    })
 6991                    .ok();
 6992            });
 6993            state.hide_task = Some(hide_task);
 6994            true
 6995        } else {
 6996            false
 6997        }
 6998    }
 6999
 7000    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7001        if self.pending_rename.is_some() {
 7002            return None;
 7003        }
 7004
 7005        let provider = self.semantics_provider.clone()?;
 7006        let buffer = self.buffer.read(cx);
 7007        let newest_selection = self.selections.newest_anchor().clone();
 7008        let cursor_position = newest_selection.head();
 7009        let (cursor_buffer, cursor_buffer_position) =
 7010            buffer.text_anchor_for_position(cursor_position, cx)?;
 7011        let (tail_buffer, tail_buffer_position) =
 7012            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7013        if cursor_buffer != tail_buffer {
 7014            return None;
 7015        }
 7016
 7017        let snapshot = cursor_buffer.read(cx).snapshot();
 7018        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7019        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7020        if start_word_range != end_word_range {
 7021            self.document_highlights_task.take();
 7022            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7023            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7024            return None;
 7025        }
 7026
 7027        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7028        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7029            cx.background_executor()
 7030                .timer(Duration::from_millis(debounce))
 7031                .await;
 7032
 7033            let highlights = if let Some(highlights) = cx
 7034                .update(|cx| {
 7035                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7036                })
 7037                .ok()
 7038                .flatten()
 7039            {
 7040                highlights.await.log_err()
 7041            } else {
 7042                None
 7043            };
 7044
 7045            if let Some(highlights) = highlights {
 7046                this.update(cx, |this, cx| {
 7047                    if this.pending_rename.is_some() {
 7048                        return;
 7049                    }
 7050
 7051                    let buffer = this.buffer.read(cx);
 7052                    if buffer
 7053                        .text_anchor_for_position(cursor_position, cx)
 7054                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7055                    {
 7056                        return;
 7057                    }
 7058
 7059                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7060                    let mut write_ranges = Vec::new();
 7061                    let mut read_ranges = Vec::new();
 7062                    for highlight in highlights {
 7063                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7064                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7065                        {
 7066                            let start = highlight
 7067                                .range
 7068                                .start
 7069                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7070                            let end = highlight
 7071                                .range
 7072                                .end
 7073                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7074                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7075                                continue;
 7076                            }
 7077
 7078                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7079                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7080                                write_ranges.push(range);
 7081                            } else {
 7082                                read_ranges.push(range);
 7083                            }
 7084                        }
 7085                    }
 7086
 7087                    this.highlight_background::<DocumentHighlightRead>(
 7088                        &read_ranges,
 7089                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7090                        cx,
 7091                    );
 7092                    this.highlight_background::<DocumentHighlightWrite>(
 7093                        &write_ranges,
 7094                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7095                        cx,
 7096                    );
 7097                    cx.notify();
 7098                })
 7099                .log_err();
 7100            }
 7101        }));
 7102        None
 7103    }
 7104
 7105    fn prepare_highlight_query_from_selection(
 7106        &mut self,
 7107        window: &Window,
 7108        cx: &mut Context<Editor>,
 7109    ) -> Option<(String, Range<Anchor>)> {
 7110        if matches!(self.mode, EditorMode::SingleLine) {
 7111            return None;
 7112        }
 7113        if !EditorSettings::get_global(cx).selection_highlight {
 7114            return None;
 7115        }
 7116        if self.selections.count() != 1 || self.selections.line_mode() {
 7117            return None;
 7118        }
 7119        let snapshot = self.snapshot(window, cx);
 7120        let selection = self.selections.newest::<Point>(&snapshot);
 7121        // If the selection spans multiple rows OR it is empty
 7122        if selection.start.row != selection.end.row
 7123            || selection.start.column == selection.end.column
 7124        {
 7125            return None;
 7126        }
 7127        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7128        let query = snapshot
 7129            .buffer_snapshot()
 7130            .text_for_range(selection_anchor_range.clone())
 7131            .collect::<String>();
 7132        if query.trim().is_empty() {
 7133            return None;
 7134        }
 7135        Some((query, selection_anchor_range))
 7136    }
 7137
 7138    fn update_selection_occurrence_highlights(
 7139        &mut self,
 7140        query_text: String,
 7141        query_range: Range<Anchor>,
 7142        multi_buffer_range_to_query: Range<Point>,
 7143        use_debounce: bool,
 7144        window: &mut Window,
 7145        cx: &mut Context<Editor>,
 7146    ) -> Task<()> {
 7147        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7148        cx.spawn_in(window, async move |editor, cx| {
 7149            if use_debounce {
 7150                cx.background_executor()
 7151                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7152                    .await;
 7153            }
 7154            let match_task = cx.background_spawn(async move {
 7155                let buffer_ranges = multi_buffer_snapshot
 7156                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7157                    .into_iter()
 7158                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7159                let mut match_ranges = Vec::new();
 7160                let Ok(regex) = project::search::SearchQuery::text(
 7161                    query_text.clone(),
 7162                    false,
 7163                    false,
 7164                    false,
 7165                    Default::default(),
 7166                    Default::default(),
 7167                    false,
 7168                    None,
 7169                ) else {
 7170                    return Vec::default();
 7171                };
 7172                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7173                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7174                    match_ranges.extend(
 7175                        regex
 7176                            .search(
 7177                                buffer_snapshot,
 7178                                Some(search_range.start.0..search_range.end.0),
 7179                            )
 7180                            .await
 7181                            .into_iter()
 7182                            .filter_map(|match_range| {
 7183                                let match_start = buffer_snapshot
 7184                                    .anchor_after(search_range.start + match_range.start);
 7185                                let match_end = buffer_snapshot
 7186                                    .anchor_before(search_range.start + match_range.end);
 7187                                let match_anchor_range =
 7188                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7189                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7190                            }),
 7191                    );
 7192                }
 7193                match_ranges
 7194            });
 7195            let match_ranges = match_task.await;
 7196            editor
 7197                .update_in(cx, |editor, _, cx| {
 7198                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7199                    if !match_ranges.is_empty() {
 7200                        editor.highlight_background::<SelectedTextHighlight>(
 7201                            &match_ranges,
 7202                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7203                            cx,
 7204                        )
 7205                    }
 7206                })
 7207                .log_err();
 7208        })
 7209    }
 7210
 7211    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7212        struct NewlineFold;
 7213        let type_id = std::any::TypeId::of::<NewlineFold>();
 7214        if !self.mode.is_single_line() {
 7215            return;
 7216        }
 7217        let snapshot = self.snapshot(window, cx);
 7218        if snapshot.buffer_snapshot().max_point().row == 0 {
 7219            return;
 7220        }
 7221        let task = cx.background_spawn(async move {
 7222            let new_newlines = snapshot
 7223                .buffer_chars_at(MultiBufferOffset(0))
 7224                .filter_map(|(c, i)| {
 7225                    if c == '\n' {
 7226                        Some(
 7227                            snapshot.buffer_snapshot().anchor_after(i)
 7228                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7229                        )
 7230                    } else {
 7231                        None
 7232                    }
 7233                })
 7234                .collect::<Vec<_>>();
 7235            let existing_newlines = snapshot
 7236                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7237                .filter_map(|fold| {
 7238                    if fold.placeholder.type_tag == Some(type_id) {
 7239                        Some(fold.range.start..fold.range.end)
 7240                    } else {
 7241                        None
 7242                    }
 7243                })
 7244                .collect::<Vec<_>>();
 7245
 7246            (new_newlines, existing_newlines)
 7247        });
 7248        self.folding_newlines = cx.spawn(async move |this, cx| {
 7249            let (new_newlines, existing_newlines) = task.await;
 7250            if new_newlines == existing_newlines {
 7251                return;
 7252            }
 7253            let placeholder = FoldPlaceholder {
 7254                render: Arc::new(move |_, _, cx| {
 7255                    div()
 7256                        .bg(cx.theme().status().hint_background)
 7257                        .border_b_1()
 7258                        .size_full()
 7259                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7260                        .border_color(cx.theme().status().hint)
 7261                        .child("\\n")
 7262                        .into_any()
 7263                }),
 7264                constrain_width: false,
 7265                merge_adjacent: false,
 7266                type_tag: Some(type_id),
 7267            };
 7268            let creases = new_newlines
 7269                .into_iter()
 7270                .map(|range| Crease::simple(range, placeholder.clone()))
 7271                .collect();
 7272            this.update(cx, |this, cx| {
 7273                this.display_map.update(cx, |display_map, cx| {
 7274                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7275                    display_map.fold(creases, cx);
 7276                });
 7277            })
 7278            .ok();
 7279        });
 7280    }
 7281
 7282    fn refresh_selected_text_highlights(
 7283        &mut self,
 7284        on_buffer_edit: bool,
 7285        window: &mut Window,
 7286        cx: &mut Context<Editor>,
 7287    ) {
 7288        let Some((query_text, query_range)) =
 7289            self.prepare_highlight_query_from_selection(window, cx)
 7290        else {
 7291            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7292            self.quick_selection_highlight_task.take();
 7293            self.debounced_selection_highlight_task.take();
 7294            return;
 7295        };
 7296        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7297        if on_buffer_edit
 7298            || self
 7299                .quick_selection_highlight_task
 7300                .as_ref()
 7301                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7302        {
 7303            let multi_buffer_visible_start = self
 7304                .scroll_manager
 7305                .anchor()
 7306                .anchor
 7307                .to_point(&multi_buffer_snapshot);
 7308            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7309                multi_buffer_visible_start
 7310                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7311                Bias::Left,
 7312            );
 7313            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7314            self.quick_selection_highlight_task = Some((
 7315                query_range.clone(),
 7316                self.update_selection_occurrence_highlights(
 7317                    query_text.clone(),
 7318                    query_range.clone(),
 7319                    multi_buffer_visible_range,
 7320                    false,
 7321                    window,
 7322                    cx,
 7323                ),
 7324            ));
 7325        }
 7326        if on_buffer_edit
 7327            || self
 7328                .debounced_selection_highlight_task
 7329                .as_ref()
 7330                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7331        {
 7332            let multi_buffer_start = multi_buffer_snapshot
 7333                .anchor_before(MultiBufferOffset(0))
 7334                .to_point(&multi_buffer_snapshot);
 7335            let multi_buffer_end = multi_buffer_snapshot
 7336                .anchor_after(multi_buffer_snapshot.len())
 7337                .to_point(&multi_buffer_snapshot);
 7338            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7339            self.debounced_selection_highlight_task = Some((
 7340                query_range.clone(),
 7341                self.update_selection_occurrence_highlights(
 7342                    query_text,
 7343                    query_range,
 7344                    multi_buffer_full_range,
 7345                    true,
 7346                    window,
 7347                    cx,
 7348                ),
 7349            ));
 7350        }
 7351    }
 7352
 7353    pub fn refresh_edit_prediction(
 7354        &mut self,
 7355        debounce: bool,
 7356        user_requested: bool,
 7357        window: &mut Window,
 7358        cx: &mut Context<Self>,
 7359    ) -> Option<()> {
 7360        if DisableAiSettings::get_global(cx).disable_ai {
 7361            return None;
 7362        }
 7363
 7364        let provider = self.edit_prediction_provider()?;
 7365        let cursor = self.selections.newest_anchor().head();
 7366        let (buffer, cursor_buffer_position) =
 7367            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7368
 7369        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7370            self.discard_edit_prediction(false, cx);
 7371            return None;
 7372        }
 7373
 7374        self.update_visible_edit_prediction(window, cx);
 7375
 7376        if !user_requested
 7377            && (!self.should_show_edit_predictions()
 7378                || !self.is_focused(window)
 7379                || buffer.read(cx).is_empty())
 7380        {
 7381            self.discard_edit_prediction(false, cx);
 7382            return None;
 7383        }
 7384
 7385        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7386        Some(())
 7387    }
 7388
 7389    fn show_edit_predictions_in_menu(&self) -> bool {
 7390        match self.edit_prediction_settings {
 7391            EditPredictionSettings::Disabled => false,
 7392            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7393        }
 7394    }
 7395
 7396    pub fn edit_predictions_enabled(&self) -> bool {
 7397        match self.edit_prediction_settings {
 7398            EditPredictionSettings::Disabled => false,
 7399            EditPredictionSettings::Enabled { .. } => true,
 7400        }
 7401    }
 7402
 7403    fn edit_prediction_requires_modifier(&self) -> bool {
 7404        match self.edit_prediction_settings {
 7405            EditPredictionSettings::Disabled => false,
 7406            EditPredictionSettings::Enabled {
 7407                preview_requires_modifier,
 7408                ..
 7409            } => preview_requires_modifier,
 7410        }
 7411    }
 7412
 7413    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7414        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7415            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7416            self.discard_edit_prediction(false, cx);
 7417        } else {
 7418            let selection = self.selections.newest_anchor();
 7419            let cursor = selection.head();
 7420
 7421            if let Some((buffer, cursor_buffer_position)) =
 7422                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7423            {
 7424                self.edit_prediction_settings =
 7425                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7426            }
 7427        }
 7428    }
 7429
 7430    fn edit_prediction_settings_at_position(
 7431        &self,
 7432        buffer: &Entity<Buffer>,
 7433        buffer_position: language::Anchor,
 7434        cx: &App,
 7435    ) -> EditPredictionSettings {
 7436        if !self.mode.is_full()
 7437            || !self.show_edit_predictions_override.unwrap_or(true)
 7438            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7439        {
 7440            return EditPredictionSettings::Disabled;
 7441        }
 7442
 7443        let buffer = buffer.read(cx);
 7444
 7445        let file = buffer.file();
 7446
 7447        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7448            return EditPredictionSettings::Disabled;
 7449        };
 7450
 7451        let by_provider = matches!(
 7452            self.menu_edit_predictions_policy,
 7453            MenuEditPredictionsPolicy::ByProvider
 7454        );
 7455
 7456        let show_in_menu = by_provider
 7457            && self
 7458                .edit_prediction_provider
 7459                .as_ref()
 7460                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7461
 7462        let preview_requires_modifier =
 7463            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7464
 7465        EditPredictionSettings::Enabled {
 7466            show_in_menu,
 7467            preview_requires_modifier,
 7468        }
 7469    }
 7470
 7471    fn should_show_edit_predictions(&self) -> bool {
 7472        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7473    }
 7474
 7475    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7476        matches!(
 7477            self.edit_prediction_preview,
 7478            EditPredictionPreview::Active { .. }
 7479        )
 7480    }
 7481
 7482    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7483        let cursor = self.selections.newest_anchor().head();
 7484        if let Some((buffer, cursor_position)) =
 7485            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7486        {
 7487            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7488        } else {
 7489            false
 7490        }
 7491    }
 7492
 7493    pub fn supports_minimap(&self, cx: &App) -> bool {
 7494        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7495    }
 7496
 7497    fn edit_predictions_enabled_in_buffer(
 7498        &self,
 7499        buffer: &Entity<Buffer>,
 7500        buffer_position: language::Anchor,
 7501        cx: &App,
 7502    ) -> bool {
 7503        maybe!({
 7504            if self.read_only(cx) {
 7505                return Some(false);
 7506            }
 7507            let provider = self.edit_prediction_provider()?;
 7508            if !provider.is_enabled(buffer, buffer_position, cx) {
 7509                return Some(false);
 7510            }
 7511            let buffer = buffer.read(cx);
 7512            let Some(file) = buffer.file() else {
 7513                return Some(true);
 7514            };
 7515            let settings = all_language_settings(Some(file), cx);
 7516            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7517        })
 7518        .unwrap_or(false)
 7519    }
 7520
 7521    fn cycle_edit_prediction(
 7522        &mut self,
 7523        direction: Direction,
 7524        window: &mut Window,
 7525        cx: &mut Context<Self>,
 7526    ) -> Option<()> {
 7527        let provider = self.edit_prediction_provider()?;
 7528        let cursor = self.selections.newest_anchor().head();
 7529        let (buffer, cursor_buffer_position) =
 7530            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7531        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7532            return None;
 7533        }
 7534
 7535        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7536        self.update_visible_edit_prediction(window, cx);
 7537
 7538        Some(())
 7539    }
 7540
 7541    pub fn show_edit_prediction(
 7542        &mut self,
 7543        _: &ShowEditPrediction,
 7544        window: &mut Window,
 7545        cx: &mut Context<Self>,
 7546    ) {
 7547        if !self.has_active_edit_prediction() {
 7548            self.refresh_edit_prediction(false, true, window, cx);
 7549            return;
 7550        }
 7551
 7552        self.update_visible_edit_prediction(window, cx);
 7553    }
 7554
 7555    pub fn display_cursor_names(
 7556        &mut self,
 7557        _: &DisplayCursorNames,
 7558        window: &mut Window,
 7559        cx: &mut Context<Self>,
 7560    ) {
 7561        self.show_cursor_names(window, cx);
 7562    }
 7563
 7564    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7565        self.show_cursor_names = true;
 7566        cx.notify();
 7567        cx.spawn_in(window, async move |this, cx| {
 7568            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7569            this.update(cx, |this, cx| {
 7570                this.show_cursor_names = false;
 7571                cx.notify()
 7572            })
 7573            .ok()
 7574        })
 7575        .detach();
 7576    }
 7577
 7578    pub fn next_edit_prediction(
 7579        &mut self,
 7580        _: &NextEditPrediction,
 7581        window: &mut Window,
 7582        cx: &mut Context<Self>,
 7583    ) {
 7584        if self.has_active_edit_prediction() {
 7585            self.cycle_edit_prediction(Direction::Next, window, cx);
 7586        } else {
 7587            let is_copilot_disabled = self
 7588                .refresh_edit_prediction(false, true, window, cx)
 7589                .is_none();
 7590            if is_copilot_disabled {
 7591                cx.propagate();
 7592            }
 7593        }
 7594    }
 7595
 7596    pub fn previous_edit_prediction(
 7597        &mut self,
 7598        _: &PreviousEditPrediction,
 7599        window: &mut Window,
 7600        cx: &mut Context<Self>,
 7601    ) {
 7602        if self.has_active_edit_prediction() {
 7603            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7604        } else {
 7605            let is_copilot_disabled = self
 7606                .refresh_edit_prediction(false, true, window, cx)
 7607                .is_none();
 7608            if is_copilot_disabled {
 7609                cx.propagate();
 7610            }
 7611        }
 7612    }
 7613
 7614    pub fn accept_edit_prediction(
 7615        &mut self,
 7616        _: &AcceptEditPrediction,
 7617        window: &mut Window,
 7618        cx: &mut Context<Self>,
 7619    ) {
 7620        if self.show_edit_predictions_in_menu() {
 7621            self.hide_context_menu(window, cx);
 7622        }
 7623
 7624        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7625            return;
 7626        };
 7627
 7628        match &active_edit_prediction.completion {
 7629            EditPrediction::MoveWithin { target, .. } => {
 7630                let target = *target;
 7631
 7632                if let Some(position_map) = &self.last_position_map {
 7633                    if position_map
 7634                        .visible_row_range
 7635                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7636                        || !self.edit_prediction_requires_modifier()
 7637                    {
 7638                        self.unfold_ranges(&[target..target], true, false, cx);
 7639                        // Note that this is also done in vim's handler of the Tab action.
 7640                        self.change_selections(
 7641                            SelectionEffects::scroll(Autoscroll::newest()),
 7642                            window,
 7643                            cx,
 7644                            |selections| {
 7645                                selections.select_anchor_ranges([target..target]);
 7646                            },
 7647                        );
 7648                        self.clear_row_highlights::<EditPredictionPreview>();
 7649
 7650                        self.edit_prediction_preview
 7651                            .set_previous_scroll_position(None);
 7652                    } else {
 7653                        self.edit_prediction_preview
 7654                            .set_previous_scroll_position(Some(
 7655                                position_map.snapshot.scroll_anchor,
 7656                            ));
 7657
 7658                        self.highlight_rows::<EditPredictionPreview>(
 7659                            target..target,
 7660                            cx.theme().colors().editor_highlighted_line_background,
 7661                            RowHighlightOptions {
 7662                                autoscroll: true,
 7663                                ..Default::default()
 7664                            },
 7665                            cx,
 7666                        );
 7667                        self.request_autoscroll(Autoscroll::fit(), cx);
 7668                    }
 7669                }
 7670            }
 7671            EditPrediction::MoveOutside { snapshot, target } => {
 7672                if let Some(workspace) = self.workspace() {
 7673                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7674                        .detach_and_log_err(cx);
 7675                }
 7676            }
 7677            EditPrediction::Edit { edits, .. } => {
 7678                self.report_edit_prediction_event(
 7679                    active_edit_prediction.completion_id.clone(),
 7680                    true,
 7681                    cx,
 7682                );
 7683
 7684                if let Some(provider) = self.edit_prediction_provider() {
 7685                    provider.accept(cx);
 7686                }
 7687
 7688                // Store the transaction ID and selections before applying the edit
 7689                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7690
 7691                let snapshot = self.buffer.read(cx).snapshot(cx);
 7692                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7693
 7694                self.buffer.update(cx, |buffer, cx| {
 7695                    buffer.edit(edits.iter().cloned(), None, cx)
 7696                });
 7697
 7698                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7699                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7700                });
 7701
 7702                let selections = self.selections.disjoint_anchors_arc();
 7703                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7704                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7705                    if has_new_transaction {
 7706                        self.selection_history
 7707                            .insert_transaction(transaction_id_now, selections);
 7708                    }
 7709                }
 7710
 7711                self.update_visible_edit_prediction(window, cx);
 7712                if self.active_edit_prediction.is_none() {
 7713                    self.refresh_edit_prediction(true, true, window, cx);
 7714                }
 7715
 7716                cx.notify();
 7717            }
 7718        }
 7719
 7720        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7721    }
 7722
 7723    pub fn accept_partial_edit_prediction(
 7724        &mut self,
 7725        _: &AcceptPartialEditPrediction,
 7726        window: &mut Window,
 7727        cx: &mut Context<Self>,
 7728    ) {
 7729        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7730            return;
 7731        };
 7732        if self.selections.count() != 1 {
 7733            return;
 7734        }
 7735
 7736        match &active_edit_prediction.completion {
 7737            EditPrediction::MoveWithin { target, .. } => {
 7738                let target = *target;
 7739                self.change_selections(
 7740                    SelectionEffects::scroll(Autoscroll::newest()),
 7741                    window,
 7742                    cx,
 7743                    |selections| {
 7744                        selections.select_anchor_ranges([target..target]);
 7745                    },
 7746                );
 7747            }
 7748            EditPrediction::MoveOutside { snapshot, target } => {
 7749                if let Some(workspace) = self.workspace() {
 7750                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7751                        .detach_and_log_err(cx);
 7752                }
 7753            }
 7754            EditPrediction::Edit { edits, .. } => {
 7755                self.report_edit_prediction_event(
 7756                    active_edit_prediction.completion_id.clone(),
 7757                    true,
 7758                    cx,
 7759                );
 7760
 7761                // Find an insertion that starts at the cursor position.
 7762                let snapshot = self.buffer.read(cx).snapshot(cx);
 7763                let cursor_offset = self
 7764                    .selections
 7765                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7766                    .head();
 7767                let insertion = edits.iter().find_map(|(range, text)| {
 7768                    let range = range.to_offset(&snapshot);
 7769                    if range.is_empty() && range.start == cursor_offset {
 7770                        Some(text)
 7771                    } else {
 7772                        None
 7773                    }
 7774                });
 7775
 7776                if let Some(text) = insertion {
 7777                    let mut partial_completion = text
 7778                        .chars()
 7779                        .by_ref()
 7780                        .take_while(|c| c.is_alphabetic())
 7781                        .collect::<String>();
 7782                    if partial_completion.is_empty() {
 7783                        partial_completion = text
 7784                            .chars()
 7785                            .by_ref()
 7786                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7787                            .collect::<String>();
 7788                    }
 7789
 7790                    cx.emit(EditorEvent::InputHandled {
 7791                        utf16_range_to_replace: None,
 7792                        text: partial_completion.clone().into(),
 7793                    });
 7794
 7795                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7796
 7797                    self.refresh_edit_prediction(true, true, window, cx);
 7798                    cx.notify();
 7799                } else {
 7800                    self.accept_edit_prediction(&Default::default(), window, cx);
 7801                }
 7802            }
 7803        }
 7804    }
 7805
 7806    fn discard_edit_prediction(
 7807        &mut self,
 7808        should_report_edit_prediction_event: bool,
 7809        cx: &mut Context<Self>,
 7810    ) -> bool {
 7811        if should_report_edit_prediction_event {
 7812            let completion_id = self
 7813                .active_edit_prediction
 7814                .as_ref()
 7815                .and_then(|active_completion| active_completion.completion_id.clone());
 7816
 7817            self.report_edit_prediction_event(completion_id, false, cx);
 7818        }
 7819
 7820        if let Some(provider) = self.edit_prediction_provider() {
 7821            provider.discard(cx);
 7822        }
 7823
 7824        self.take_active_edit_prediction(cx)
 7825    }
 7826
 7827    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7828        let Some(provider) = self.edit_prediction_provider() else {
 7829            return;
 7830        };
 7831
 7832        let Some((_, buffer, _)) = self
 7833            .buffer
 7834            .read(cx)
 7835            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7836        else {
 7837            return;
 7838        };
 7839
 7840        let extension = buffer
 7841            .read(cx)
 7842            .file()
 7843            .and_then(|file| Some(file.path().extension()?.to_string()));
 7844
 7845        let event_type = match accepted {
 7846            true => "Edit Prediction Accepted",
 7847            false => "Edit Prediction Discarded",
 7848        };
 7849        telemetry::event!(
 7850            event_type,
 7851            provider = provider.name(),
 7852            prediction_id = id,
 7853            suggestion_accepted = accepted,
 7854            file_extension = extension,
 7855        );
 7856    }
 7857
 7858    fn open_editor_at_anchor(
 7859        snapshot: &language::BufferSnapshot,
 7860        target: language::Anchor,
 7861        workspace: &Entity<Workspace>,
 7862        window: &mut Window,
 7863        cx: &mut App,
 7864    ) -> Task<Result<()>> {
 7865        workspace.update(cx, |workspace, cx| {
 7866            let path = snapshot.file().map(|file| file.full_path(cx));
 7867            let Some(path) =
 7868                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7869            else {
 7870                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7871            };
 7872            let target = text::ToPoint::to_point(&target, snapshot);
 7873            let item = workspace.open_path(path, None, true, window, cx);
 7874            window.spawn(cx, async move |cx| {
 7875                let Some(editor) = item.await?.downcast::<Editor>() else {
 7876                    return Ok(());
 7877                };
 7878                editor
 7879                    .update_in(cx, |editor, window, cx| {
 7880                        editor.go_to_singleton_buffer_point(target, window, cx);
 7881                    })
 7882                    .ok();
 7883                anyhow::Ok(())
 7884            })
 7885        })
 7886    }
 7887
 7888    pub fn has_active_edit_prediction(&self) -> bool {
 7889        self.active_edit_prediction.is_some()
 7890    }
 7891
 7892    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7893        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7894            return false;
 7895        };
 7896
 7897        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7898        self.clear_highlights::<EditPredictionHighlight>(cx);
 7899        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7900        true
 7901    }
 7902
 7903    /// Returns true when we're displaying the edit prediction popover below the cursor
 7904    /// like we are not previewing and the LSP autocomplete menu is visible
 7905    /// or we are in `when_holding_modifier` mode.
 7906    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7907        if self.edit_prediction_preview_is_active()
 7908            || !self.show_edit_predictions_in_menu()
 7909            || !self.edit_predictions_enabled()
 7910        {
 7911            return false;
 7912        }
 7913
 7914        if self.has_visible_completions_menu() {
 7915            return true;
 7916        }
 7917
 7918        has_completion && self.edit_prediction_requires_modifier()
 7919    }
 7920
 7921    fn handle_modifiers_changed(
 7922        &mut self,
 7923        modifiers: Modifiers,
 7924        position_map: &PositionMap,
 7925        window: &mut Window,
 7926        cx: &mut Context<Self>,
 7927    ) {
 7928        // Ensure that the edit prediction preview is updated, even when not
 7929        // enabled, if there's an active edit prediction preview.
 7930        if self.show_edit_predictions_in_menu()
 7931            || matches!(
 7932                self.edit_prediction_preview,
 7933                EditPredictionPreview::Active { .. }
 7934            )
 7935        {
 7936            self.update_edit_prediction_preview(&modifiers, window, cx);
 7937        }
 7938
 7939        self.update_selection_mode(&modifiers, position_map, window, cx);
 7940
 7941        let mouse_position = window.mouse_position();
 7942        if !position_map.text_hitbox.is_hovered(window) {
 7943            return;
 7944        }
 7945
 7946        self.update_hovered_link(
 7947            position_map.point_for_position(mouse_position),
 7948            &position_map.snapshot,
 7949            modifiers,
 7950            window,
 7951            cx,
 7952        )
 7953    }
 7954
 7955    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7956        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7957            MultiCursorModifier::Alt => modifiers.secondary(),
 7958            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7959        }
 7960    }
 7961
 7962    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7963        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7964            MultiCursorModifier::Alt => modifiers.alt,
 7965            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7966        }
 7967    }
 7968
 7969    fn columnar_selection_mode(
 7970        modifiers: &Modifiers,
 7971        cx: &mut Context<Self>,
 7972    ) -> Option<ColumnarMode> {
 7973        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7974            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7975                Some(ColumnarMode::FromMouse)
 7976            } else if Self::is_alt_pressed(modifiers, cx) {
 7977                Some(ColumnarMode::FromSelection)
 7978            } else {
 7979                None
 7980            }
 7981        } else {
 7982            None
 7983        }
 7984    }
 7985
 7986    fn update_selection_mode(
 7987        &mut self,
 7988        modifiers: &Modifiers,
 7989        position_map: &PositionMap,
 7990        window: &mut Window,
 7991        cx: &mut Context<Self>,
 7992    ) {
 7993        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7994            return;
 7995        };
 7996        if self.selections.pending_anchor().is_none() {
 7997            return;
 7998        }
 7999
 8000        let mouse_position = window.mouse_position();
 8001        let point_for_position = position_map.point_for_position(mouse_position);
 8002        let position = point_for_position.previous_valid;
 8003
 8004        self.select(
 8005            SelectPhase::BeginColumnar {
 8006                position,
 8007                reset: false,
 8008                mode,
 8009                goal_column: point_for_position.exact_unclipped.column(),
 8010            },
 8011            window,
 8012            cx,
 8013        );
 8014    }
 8015
 8016    fn update_edit_prediction_preview(
 8017        &mut self,
 8018        modifiers: &Modifiers,
 8019        window: &mut Window,
 8020        cx: &mut Context<Self>,
 8021    ) {
 8022        let mut modifiers_held = false;
 8023        if let Some(accept_keystroke) = self
 8024            .accept_edit_prediction_keybind(false, window, cx)
 8025            .keystroke()
 8026        {
 8027            modifiers_held = modifiers_held
 8028                || (accept_keystroke.modifiers() == modifiers
 8029                    && accept_keystroke.modifiers().modified());
 8030        };
 8031        if let Some(accept_partial_keystroke) = self
 8032            .accept_edit_prediction_keybind(true, window, cx)
 8033            .keystroke()
 8034        {
 8035            modifiers_held = modifiers_held
 8036                || (accept_partial_keystroke.modifiers() == modifiers
 8037                    && accept_partial_keystroke.modifiers().modified());
 8038        }
 8039
 8040        if modifiers_held {
 8041            if matches!(
 8042                self.edit_prediction_preview,
 8043                EditPredictionPreview::Inactive { .. }
 8044            ) {
 8045                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 8046                    provider.provider.did_show(cx)
 8047                }
 8048
 8049                self.edit_prediction_preview = EditPredictionPreview::Active {
 8050                    previous_scroll_position: None,
 8051                    since: Instant::now(),
 8052                };
 8053
 8054                self.update_visible_edit_prediction(window, cx);
 8055                cx.notify();
 8056            }
 8057        } else if let EditPredictionPreview::Active {
 8058            previous_scroll_position,
 8059            since,
 8060        } = self.edit_prediction_preview
 8061        {
 8062            if let (Some(previous_scroll_position), Some(position_map)) =
 8063                (previous_scroll_position, self.last_position_map.as_ref())
 8064            {
 8065                self.set_scroll_position(
 8066                    previous_scroll_position
 8067                        .scroll_position(&position_map.snapshot.display_snapshot),
 8068                    window,
 8069                    cx,
 8070                );
 8071            }
 8072
 8073            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8074                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8075            };
 8076            self.clear_row_highlights::<EditPredictionPreview>();
 8077            self.update_visible_edit_prediction(window, cx);
 8078            cx.notify();
 8079        }
 8080    }
 8081
 8082    fn update_visible_edit_prediction(
 8083        &mut self,
 8084        _window: &mut Window,
 8085        cx: &mut Context<Self>,
 8086    ) -> Option<()> {
 8087        if DisableAiSettings::get_global(cx).disable_ai {
 8088            return None;
 8089        }
 8090
 8091        if self.ime_transaction.is_some() {
 8092            self.discard_edit_prediction(false, cx);
 8093            return None;
 8094        }
 8095
 8096        let selection = self.selections.newest_anchor();
 8097        let cursor = selection.head();
 8098        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8099        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8100        let excerpt_id = cursor.excerpt_id;
 8101
 8102        let show_in_menu = self.show_edit_predictions_in_menu();
 8103        let completions_menu_has_precedence = !show_in_menu
 8104            && (self.context_menu.borrow().is_some()
 8105                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8106
 8107        if completions_menu_has_precedence
 8108            || !offset_selection.is_empty()
 8109            || self
 8110                .active_edit_prediction
 8111                .as_ref()
 8112                .is_some_and(|completion| {
 8113                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8114                        return false;
 8115                    };
 8116                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8117                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8118                    !invalidation_range.contains(&offset_selection.head())
 8119                })
 8120        {
 8121            self.discard_edit_prediction(false, cx);
 8122            return None;
 8123        }
 8124
 8125        self.take_active_edit_prediction(cx);
 8126        let Some(provider) = self.edit_prediction_provider() else {
 8127            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8128            return None;
 8129        };
 8130
 8131        let (buffer, cursor_buffer_position) =
 8132            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8133
 8134        self.edit_prediction_settings =
 8135            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8136
 8137        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8138
 8139        if self.edit_prediction_indent_conflict {
 8140            let cursor_point = cursor.to_point(&multibuffer);
 8141            let mut suggested_indent = None;
 8142            multibuffer.suggested_indents_callback(
 8143                cursor_point.row..cursor_point.row + 1,
 8144                |_, indent| {
 8145                    suggested_indent = Some(indent);
 8146                    ControlFlow::Break(())
 8147                },
 8148                cx,
 8149            );
 8150
 8151            if let Some(indent) = suggested_indent
 8152                && indent.len == cursor_point.column
 8153            {
 8154                self.edit_prediction_indent_conflict = false;
 8155            }
 8156        }
 8157
 8158        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8159
 8160        let (completion_id, edits, edit_preview) = match edit_prediction {
 8161            edit_prediction_types::EditPrediction::Local {
 8162                id,
 8163                edits,
 8164                edit_preview,
 8165            } => (id, edits, edit_preview),
 8166            edit_prediction_types::EditPrediction::Jump {
 8167                id,
 8168                snapshot,
 8169                target,
 8170            } => {
 8171                self.stale_edit_prediction_in_menu = None;
 8172                self.active_edit_prediction = Some(EditPredictionState {
 8173                    inlay_ids: vec![],
 8174                    completion: EditPrediction::MoveOutside { snapshot, target },
 8175                    completion_id: id,
 8176                    invalidation_range: None,
 8177                });
 8178                cx.notify();
 8179                return Some(());
 8180            }
 8181        };
 8182
 8183        let edits = edits
 8184            .into_iter()
 8185            .flat_map(|(range, new_text)| {
 8186                Some((
 8187                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8188                    new_text,
 8189                ))
 8190            })
 8191            .collect::<Vec<_>>();
 8192        if edits.is_empty() {
 8193            return None;
 8194        }
 8195
 8196        let first_edit_start = edits.first().unwrap().0.start;
 8197        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8198        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8199
 8200        let last_edit_end = edits.last().unwrap().0.end;
 8201        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8202        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8203
 8204        let cursor_row = cursor.to_point(&multibuffer).row;
 8205
 8206        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8207
 8208        let mut inlay_ids = Vec::new();
 8209        let invalidation_row_range;
 8210        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8211            Some(cursor_row..edit_end_row)
 8212        } else if cursor_row > edit_end_row {
 8213            Some(edit_start_row..cursor_row)
 8214        } else {
 8215            None
 8216        };
 8217        let supports_jump = self
 8218            .edit_prediction_provider
 8219            .as_ref()
 8220            .map(|provider| provider.provider.supports_jump_to_edit())
 8221            .unwrap_or(true);
 8222
 8223        let is_move = supports_jump
 8224            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8225        let completion = if is_move {
 8226            invalidation_row_range =
 8227                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8228            let target = first_edit_start;
 8229            EditPrediction::MoveWithin { target, snapshot }
 8230        } else {
 8231            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8232                && !self.edit_predictions_hidden_for_vim_mode;
 8233
 8234            if show_completions_in_buffer {
 8235                if let Some(provider) = &self.edit_prediction_provider {
 8236                    provider.provider.did_show(cx);
 8237                }
 8238                if edits
 8239                    .iter()
 8240                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8241                {
 8242                    let mut inlays = Vec::new();
 8243                    for (range, new_text) in &edits {
 8244                        let inlay = Inlay::edit_prediction(
 8245                            post_inc(&mut self.next_inlay_id),
 8246                            range.start,
 8247                            new_text.as_ref(),
 8248                        );
 8249                        inlay_ids.push(inlay.id);
 8250                        inlays.push(inlay);
 8251                    }
 8252
 8253                    self.splice_inlays(&[], inlays, cx);
 8254                } else {
 8255                    let background_color = cx.theme().status().deleted_background;
 8256                    self.highlight_text::<EditPredictionHighlight>(
 8257                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8258                        HighlightStyle {
 8259                            background_color: Some(background_color),
 8260                            ..Default::default()
 8261                        },
 8262                        cx,
 8263                    );
 8264                }
 8265            }
 8266
 8267            invalidation_row_range = edit_start_row..edit_end_row;
 8268
 8269            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8270                if provider.show_tab_accept_marker() {
 8271                    EditDisplayMode::TabAccept
 8272                } else {
 8273                    EditDisplayMode::Inline
 8274                }
 8275            } else {
 8276                EditDisplayMode::DiffPopover
 8277            };
 8278
 8279            EditPrediction::Edit {
 8280                edits,
 8281                edit_preview,
 8282                display_mode,
 8283                snapshot,
 8284            }
 8285        };
 8286
 8287        let invalidation_range = multibuffer
 8288            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8289            ..multibuffer.anchor_after(Point::new(
 8290                invalidation_row_range.end,
 8291                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8292            ));
 8293
 8294        self.stale_edit_prediction_in_menu = None;
 8295        self.active_edit_prediction = Some(EditPredictionState {
 8296            inlay_ids,
 8297            completion,
 8298            completion_id,
 8299            invalidation_range: Some(invalidation_range),
 8300        });
 8301
 8302        cx.notify();
 8303
 8304        Some(())
 8305    }
 8306
 8307    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8308        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8309    }
 8310
 8311    fn clear_tasks(&mut self) {
 8312        self.tasks.clear()
 8313    }
 8314
 8315    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8316        if self.tasks.insert(key, value).is_some() {
 8317            // This case should hopefully be rare, but just in case...
 8318            log::error!(
 8319                "multiple different run targets found on a single line, only the last target will be rendered"
 8320            )
 8321        }
 8322    }
 8323
 8324    /// Get all display points of breakpoints that will be rendered within editor
 8325    ///
 8326    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8327    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8328    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8329    fn active_breakpoints(
 8330        &self,
 8331        range: Range<DisplayRow>,
 8332        window: &mut Window,
 8333        cx: &mut Context<Self>,
 8334    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8335        let mut breakpoint_display_points = HashMap::default();
 8336
 8337        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8338            return breakpoint_display_points;
 8339        };
 8340
 8341        let snapshot = self.snapshot(window, cx);
 8342
 8343        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8344        let Some(project) = self.project() else {
 8345            return breakpoint_display_points;
 8346        };
 8347
 8348        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8349            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8350
 8351        for (buffer_snapshot, range, excerpt_id) in
 8352            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8353        {
 8354            let Some(buffer) = project
 8355                .read(cx)
 8356                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8357            else {
 8358                continue;
 8359            };
 8360            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8361                &buffer,
 8362                Some(
 8363                    buffer_snapshot.anchor_before(range.start)
 8364                        ..buffer_snapshot.anchor_after(range.end),
 8365                ),
 8366                buffer_snapshot,
 8367                cx,
 8368            );
 8369            for (breakpoint, state) in breakpoints {
 8370                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8371                let position = multi_buffer_anchor
 8372                    .to_point(&multi_buffer_snapshot)
 8373                    .to_display_point(&snapshot);
 8374
 8375                breakpoint_display_points.insert(
 8376                    position.row(),
 8377                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8378                );
 8379            }
 8380        }
 8381
 8382        breakpoint_display_points
 8383    }
 8384
 8385    fn breakpoint_context_menu(
 8386        &self,
 8387        anchor: Anchor,
 8388        window: &mut Window,
 8389        cx: &mut Context<Self>,
 8390    ) -> Entity<ui::ContextMenu> {
 8391        let weak_editor = cx.weak_entity();
 8392        let focus_handle = self.focus_handle(cx);
 8393
 8394        let row = self
 8395            .buffer
 8396            .read(cx)
 8397            .snapshot(cx)
 8398            .summary_for_anchor::<Point>(&anchor)
 8399            .row;
 8400
 8401        let breakpoint = self
 8402            .breakpoint_at_row(row, window, cx)
 8403            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8404
 8405        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8406            "Edit Log Breakpoint"
 8407        } else {
 8408            "Set Log Breakpoint"
 8409        };
 8410
 8411        let condition_breakpoint_msg = if breakpoint
 8412            .as_ref()
 8413            .is_some_and(|bp| bp.1.condition.is_some())
 8414        {
 8415            "Edit Condition Breakpoint"
 8416        } else {
 8417            "Set Condition Breakpoint"
 8418        };
 8419
 8420        let hit_condition_breakpoint_msg = if breakpoint
 8421            .as_ref()
 8422            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8423        {
 8424            "Edit Hit Condition Breakpoint"
 8425        } else {
 8426            "Set Hit Condition Breakpoint"
 8427        };
 8428
 8429        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8430            "Unset Breakpoint"
 8431        } else {
 8432            "Set Breakpoint"
 8433        };
 8434
 8435        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8436
 8437        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8438            BreakpointState::Enabled => Some("Disable"),
 8439            BreakpointState::Disabled => Some("Enable"),
 8440        });
 8441
 8442        let (anchor, breakpoint) =
 8443            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8444
 8445        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8446            menu.on_blur_subscription(Subscription::new(|| {}))
 8447                .context(focus_handle)
 8448                .when(run_to_cursor, |this| {
 8449                    let weak_editor = weak_editor.clone();
 8450                    this.entry("Run to cursor", None, move |window, cx| {
 8451                        weak_editor
 8452                            .update(cx, |editor, cx| {
 8453                                editor.change_selections(
 8454                                    SelectionEffects::no_scroll(),
 8455                                    window,
 8456                                    cx,
 8457                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8458                                );
 8459                            })
 8460                            .ok();
 8461
 8462                        window.dispatch_action(Box::new(RunToCursor), cx);
 8463                    })
 8464                    .separator()
 8465                })
 8466                .when_some(toggle_state_msg, |this, msg| {
 8467                    this.entry(msg, None, {
 8468                        let weak_editor = weak_editor.clone();
 8469                        let breakpoint = breakpoint.clone();
 8470                        move |_window, cx| {
 8471                            weak_editor
 8472                                .update(cx, |this, cx| {
 8473                                    this.edit_breakpoint_at_anchor(
 8474                                        anchor,
 8475                                        breakpoint.as_ref().clone(),
 8476                                        BreakpointEditAction::InvertState,
 8477                                        cx,
 8478                                    );
 8479                                })
 8480                                .log_err();
 8481                        }
 8482                    })
 8483                })
 8484                .entry(set_breakpoint_msg, None, {
 8485                    let weak_editor = weak_editor.clone();
 8486                    let breakpoint = breakpoint.clone();
 8487                    move |_window, cx| {
 8488                        weak_editor
 8489                            .update(cx, |this, cx| {
 8490                                this.edit_breakpoint_at_anchor(
 8491                                    anchor,
 8492                                    breakpoint.as_ref().clone(),
 8493                                    BreakpointEditAction::Toggle,
 8494                                    cx,
 8495                                );
 8496                            })
 8497                            .log_err();
 8498                    }
 8499                })
 8500                .entry(log_breakpoint_msg, None, {
 8501                    let breakpoint = breakpoint.clone();
 8502                    let weak_editor = weak_editor.clone();
 8503                    move |window, cx| {
 8504                        weak_editor
 8505                            .update(cx, |this, cx| {
 8506                                this.add_edit_breakpoint_block(
 8507                                    anchor,
 8508                                    breakpoint.as_ref(),
 8509                                    BreakpointPromptEditAction::Log,
 8510                                    window,
 8511                                    cx,
 8512                                );
 8513                            })
 8514                            .log_err();
 8515                    }
 8516                })
 8517                .entry(condition_breakpoint_msg, None, {
 8518                    let breakpoint = breakpoint.clone();
 8519                    let weak_editor = weak_editor.clone();
 8520                    move |window, cx| {
 8521                        weak_editor
 8522                            .update(cx, |this, cx| {
 8523                                this.add_edit_breakpoint_block(
 8524                                    anchor,
 8525                                    breakpoint.as_ref(),
 8526                                    BreakpointPromptEditAction::Condition,
 8527                                    window,
 8528                                    cx,
 8529                                );
 8530                            })
 8531                            .log_err();
 8532                    }
 8533                })
 8534                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8535                    weak_editor
 8536                        .update(cx, |this, cx| {
 8537                            this.add_edit_breakpoint_block(
 8538                                anchor,
 8539                                breakpoint.as_ref(),
 8540                                BreakpointPromptEditAction::HitCondition,
 8541                                window,
 8542                                cx,
 8543                            );
 8544                        })
 8545                        .log_err();
 8546                })
 8547        })
 8548    }
 8549
 8550    fn render_breakpoint(
 8551        &self,
 8552        position: Anchor,
 8553        row: DisplayRow,
 8554        breakpoint: &Breakpoint,
 8555        state: Option<BreakpointSessionState>,
 8556        cx: &mut Context<Self>,
 8557    ) -> IconButton {
 8558        let is_rejected = state.is_some_and(|s| !s.verified);
 8559        // Is it a breakpoint that shows up when hovering over gutter?
 8560        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8561            (false, false),
 8562            |PhantomBreakpointIndicator {
 8563                 is_active,
 8564                 display_row,
 8565                 collides_with_existing_breakpoint,
 8566             }| {
 8567                (
 8568                    is_active && display_row == row,
 8569                    collides_with_existing_breakpoint,
 8570                )
 8571            },
 8572        );
 8573
 8574        let (color, icon) = {
 8575            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8576                (false, false) => ui::IconName::DebugBreakpoint,
 8577                (true, false) => ui::IconName::DebugLogBreakpoint,
 8578                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8579                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8580            };
 8581
 8582            let color = cx.theme().colors();
 8583
 8584            let color = if is_phantom {
 8585                if collides_with_existing {
 8586                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8587                } else {
 8588                    Color::Hint
 8589                }
 8590            } else if is_rejected {
 8591                Color::Disabled
 8592            } else {
 8593                Color::Debugger
 8594            };
 8595
 8596            (color, icon)
 8597        };
 8598
 8599        let breakpoint = Arc::from(breakpoint.clone());
 8600
 8601        let alt_as_text = gpui::Keystroke {
 8602            modifiers: Modifiers::secondary_key(),
 8603            ..Default::default()
 8604        };
 8605        let primary_action_text = if breakpoint.is_disabled() {
 8606            "Enable breakpoint"
 8607        } else if is_phantom && !collides_with_existing {
 8608            "Set breakpoint"
 8609        } else {
 8610            "Unset breakpoint"
 8611        };
 8612        let focus_handle = self.focus_handle.clone();
 8613
 8614        let meta = if is_rejected {
 8615            SharedString::from("No executable code is associated with this line.")
 8616        } else if collides_with_existing && !breakpoint.is_disabled() {
 8617            SharedString::from(format!(
 8618                "{alt_as_text}-click to disable,\nright-click for more options."
 8619            ))
 8620        } else {
 8621            SharedString::from("Right-click for more options.")
 8622        };
 8623        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8624            .icon_size(IconSize::XSmall)
 8625            .size(ui::ButtonSize::None)
 8626            .when(is_rejected, |this| {
 8627                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8628            })
 8629            .icon_color(color)
 8630            .style(ButtonStyle::Transparent)
 8631            .on_click(cx.listener({
 8632                move |editor, event: &ClickEvent, window, cx| {
 8633                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8634                        BreakpointEditAction::InvertState
 8635                    } else {
 8636                        BreakpointEditAction::Toggle
 8637                    };
 8638
 8639                    window.focus(&editor.focus_handle(cx));
 8640                    editor.edit_breakpoint_at_anchor(
 8641                        position,
 8642                        breakpoint.as_ref().clone(),
 8643                        edit_action,
 8644                        cx,
 8645                    );
 8646                }
 8647            }))
 8648            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8649                editor.set_breakpoint_context_menu(
 8650                    row,
 8651                    Some(position),
 8652                    event.position(),
 8653                    window,
 8654                    cx,
 8655                );
 8656            }))
 8657            .tooltip(move |_window, cx| {
 8658                Tooltip::with_meta_in(
 8659                    primary_action_text,
 8660                    Some(&ToggleBreakpoint),
 8661                    meta.clone(),
 8662                    &focus_handle,
 8663                    cx,
 8664                )
 8665            })
 8666    }
 8667
 8668    fn build_tasks_context(
 8669        project: &Entity<Project>,
 8670        buffer: &Entity<Buffer>,
 8671        buffer_row: u32,
 8672        tasks: &Arc<RunnableTasks>,
 8673        cx: &mut Context<Self>,
 8674    ) -> Task<Option<task::TaskContext>> {
 8675        let position = Point::new(buffer_row, tasks.column);
 8676        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8677        let location = Location {
 8678            buffer: buffer.clone(),
 8679            range: range_start..range_start,
 8680        };
 8681        // Fill in the environmental variables from the tree-sitter captures
 8682        let mut captured_task_variables = TaskVariables::default();
 8683        for (capture_name, value) in tasks.extra_variables.clone() {
 8684            captured_task_variables.insert(
 8685                task::VariableName::Custom(capture_name.into()),
 8686                value.clone(),
 8687            );
 8688        }
 8689        project.update(cx, |project, cx| {
 8690            project.task_store().update(cx, |task_store, cx| {
 8691                task_store.task_context_for_location(captured_task_variables, location, cx)
 8692            })
 8693        })
 8694    }
 8695
 8696    pub fn spawn_nearest_task(
 8697        &mut self,
 8698        action: &SpawnNearestTask,
 8699        window: &mut Window,
 8700        cx: &mut Context<Self>,
 8701    ) {
 8702        let Some((workspace, _)) = self.workspace.clone() else {
 8703            return;
 8704        };
 8705        let Some(project) = self.project.clone() else {
 8706            return;
 8707        };
 8708
 8709        // Try to find a closest, enclosing node using tree-sitter that has a task
 8710        let Some((buffer, buffer_row, tasks)) = self
 8711            .find_enclosing_node_task(cx)
 8712            // Or find the task that's closest in row-distance.
 8713            .or_else(|| self.find_closest_task(cx))
 8714        else {
 8715            return;
 8716        };
 8717
 8718        let reveal_strategy = action.reveal;
 8719        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8720        cx.spawn_in(window, async move |_, cx| {
 8721            let context = task_context.await?;
 8722            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8723
 8724            let resolved = &mut resolved_task.resolved;
 8725            resolved.reveal = reveal_strategy;
 8726
 8727            workspace
 8728                .update_in(cx, |workspace, window, cx| {
 8729                    workspace.schedule_resolved_task(
 8730                        task_source_kind,
 8731                        resolved_task,
 8732                        false,
 8733                        window,
 8734                        cx,
 8735                    );
 8736                })
 8737                .ok()
 8738        })
 8739        .detach();
 8740    }
 8741
 8742    fn find_closest_task(
 8743        &mut self,
 8744        cx: &mut Context<Self>,
 8745    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8746        let cursor_row = self
 8747            .selections
 8748            .newest_adjusted(&self.display_snapshot(cx))
 8749            .head()
 8750            .row;
 8751
 8752        let ((buffer_id, row), tasks) = self
 8753            .tasks
 8754            .iter()
 8755            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8756
 8757        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8758        let tasks = Arc::new(tasks.to_owned());
 8759        Some((buffer, *row, tasks))
 8760    }
 8761
 8762    fn find_enclosing_node_task(
 8763        &mut self,
 8764        cx: &mut Context<Self>,
 8765    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8766        let snapshot = self.buffer.read(cx).snapshot(cx);
 8767        let offset = self
 8768            .selections
 8769            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8770            .head();
 8771        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8772        let offset = excerpt.map_offset_to_buffer(offset);
 8773        let buffer_id = excerpt.buffer().remote_id();
 8774
 8775        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8776        let mut cursor = layer.node().walk();
 8777
 8778        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8779            if cursor.node().end_byte() == offset.0 {
 8780                cursor.goto_next_sibling();
 8781            }
 8782        }
 8783
 8784        // Ascend to the smallest ancestor that contains the range and has a task.
 8785        loop {
 8786            let node = cursor.node();
 8787            let node_range = node.byte_range();
 8788            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8789
 8790            // Check if this node contains our offset
 8791            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8792                // If it contains offset, check for task
 8793                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8794                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8795                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8796                }
 8797            }
 8798
 8799            if !cursor.goto_parent() {
 8800                break;
 8801            }
 8802        }
 8803        None
 8804    }
 8805
 8806    fn render_run_indicator(
 8807        &self,
 8808        _style: &EditorStyle,
 8809        is_active: bool,
 8810        row: DisplayRow,
 8811        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8812        cx: &mut Context<Self>,
 8813    ) -> IconButton {
 8814        let color = Color::Muted;
 8815        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8816
 8817        IconButton::new(
 8818            ("run_indicator", row.0 as usize),
 8819            ui::IconName::PlayOutlined,
 8820        )
 8821        .shape(ui::IconButtonShape::Square)
 8822        .icon_size(IconSize::XSmall)
 8823        .icon_color(color)
 8824        .toggle_state(is_active)
 8825        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8826            let quick_launch = match e {
 8827                ClickEvent::Keyboard(_) => true,
 8828                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8829            };
 8830
 8831            window.focus(&editor.focus_handle(cx));
 8832            editor.toggle_code_actions(
 8833                &ToggleCodeActions {
 8834                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8835                    quick_launch,
 8836                },
 8837                window,
 8838                cx,
 8839            );
 8840        }))
 8841        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8842            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8843        }))
 8844    }
 8845
 8846    pub fn context_menu_visible(&self) -> bool {
 8847        !self.edit_prediction_preview_is_active()
 8848            && self
 8849                .context_menu
 8850                .borrow()
 8851                .as_ref()
 8852                .is_some_and(|menu| menu.visible())
 8853    }
 8854
 8855    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8856        self.context_menu
 8857            .borrow()
 8858            .as_ref()
 8859            .map(|menu| menu.origin())
 8860    }
 8861
 8862    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8863        self.context_menu_options = Some(options);
 8864    }
 8865
 8866    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8867    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8868
 8869    fn render_edit_prediction_popover(
 8870        &mut self,
 8871        text_bounds: &Bounds<Pixels>,
 8872        content_origin: gpui::Point<Pixels>,
 8873        right_margin: Pixels,
 8874        editor_snapshot: &EditorSnapshot,
 8875        visible_row_range: Range<DisplayRow>,
 8876        scroll_top: ScrollOffset,
 8877        scroll_bottom: ScrollOffset,
 8878        line_layouts: &[LineWithInvisibles],
 8879        line_height: Pixels,
 8880        scroll_position: gpui::Point<ScrollOffset>,
 8881        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8882        newest_selection_head: Option<DisplayPoint>,
 8883        editor_width: Pixels,
 8884        style: &EditorStyle,
 8885        window: &mut Window,
 8886        cx: &mut App,
 8887    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8888        if self.mode().is_minimap() {
 8889            return None;
 8890        }
 8891        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8892
 8893        if self.edit_prediction_visible_in_cursor_popover(true) {
 8894            return None;
 8895        }
 8896
 8897        match &active_edit_prediction.completion {
 8898            EditPrediction::MoveWithin { target, .. } => {
 8899                let target_display_point = target.to_display_point(editor_snapshot);
 8900
 8901                if self.edit_prediction_requires_modifier() {
 8902                    if !self.edit_prediction_preview_is_active() {
 8903                        return None;
 8904                    }
 8905
 8906                    self.render_edit_prediction_modifier_jump_popover(
 8907                        text_bounds,
 8908                        content_origin,
 8909                        visible_row_range,
 8910                        line_layouts,
 8911                        line_height,
 8912                        scroll_pixel_position,
 8913                        newest_selection_head,
 8914                        target_display_point,
 8915                        window,
 8916                        cx,
 8917                    )
 8918                } else {
 8919                    self.render_edit_prediction_eager_jump_popover(
 8920                        text_bounds,
 8921                        content_origin,
 8922                        editor_snapshot,
 8923                        visible_row_range,
 8924                        scroll_top,
 8925                        scroll_bottom,
 8926                        line_height,
 8927                        scroll_pixel_position,
 8928                        target_display_point,
 8929                        editor_width,
 8930                        window,
 8931                        cx,
 8932                    )
 8933                }
 8934            }
 8935            EditPrediction::Edit {
 8936                display_mode: EditDisplayMode::Inline,
 8937                ..
 8938            } => None,
 8939            EditPrediction::Edit {
 8940                display_mode: EditDisplayMode::TabAccept,
 8941                edits,
 8942                ..
 8943            } => {
 8944                let range = &edits.first()?.0;
 8945                let target_display_point = range.end.to_display_point(editor_snapshot);
 8946
 8947                self.render_edit_prediction_end_of_line_popover(
 8948                    "Accept",
 8949                    editor_snapshot,
 8950                    visible_row_range,
 8951                    target_display_point,
 8952                    line_height,
 8953                    scroll_pixel_position,
 8954                    content_origin,
 8955                    editor_width,
 8956                    window,
 8957                    cx,
 8958                )
 8959            }
 8960            EditPrediction::Edit {
 8961                edits,
 8962                edit_preview,
 8963                display_mode: EditDisplayMode::DiffPopover,
 8964                snapshot,
 8965            } => self.render_edit_prediction_diff_popover(
 8966                text_bounds,
 8967                content_origin,
 8968                right_margin,
 8969                editor_snapshot,
 8970                visible_row_range,
 8971                line_layouts,
 8972                line_height,
 8973                scroll_position,
 8974                scroll_pixel_position,
 8975                newest_selection_head,
 8976                editor_width,
 8977                style,
 8978                edits,
 8979                edit_preview,
 8980                snapshot,
 8981                window,
 8982                cx,
 8983            ),
 8984            EditPrediction::MoveOutside { snapshot, .. } => {
 8985                let mut element = self
 8986                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8987                    .into_any();
 8988
 8989                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8990                let origin_x = text_bounds.size.width - size.width - px(30.);
 8991                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8992                element.prepaint_at(origin, window, cx);
 8993
 8994                Some((element, origin))
 8995            }
 8996        }
 8997    }
 8998
 8999    fn render_edit_prediction_modifier_jump_popover(
 9000        &mut self,
 9001        text_bounds: &Bounds<Pixels>,
 9002        content_origin: gpui::Point<Pixels>,
 9003        visible_row_range: Range<DisplayRow>,
 9004        line_layouts: &[LineWithInvisibles],
 9005        line_height: Pixels,
 9006        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9007        newest_selection_head: Option<DisplayPoint>,
 9008        target_display_point: DisplayPoint,
 9009        window: &mut Window,
 9010        cx: &mut App,
 9011    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9012        let scrolled_content_origin =
 9013            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9014
 9015        const SCROLL_PADDING_Y: Pixels = px(12.);
 9016
 9017        if target_display_point.row() < visible_row_range.start {
 9018            return self.render_edit_prediction_scroll_popover(
 9019                |_| SCROLL_PADDING_Y,
 9020                IconName::ArrowUp,
 9021                visible_row_range,
 9022                line_layouts,
 9023                newest_selection_head,
 9024                scrolled_content_origin,
 9025                window,
 9026                cx,
 9027            );
 9028        } else if target_display_point.row() >= visible_row_range.end {
 9029            return self.render_edit_prediction_scroll_popover(
 9030                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9031                IconName::ArrowDown,
 9032                visible_row_range,
 9033                line_layouts,
 9034                newest_selection_head,
 9035                scrolled_content_origin,
 9036                window,
 9037                cx,
 9038            );
 9039        }
 9040
 9041        const POLE_WIDTH: Pixels = px(2.);
 9042
 9043        let line_layout =
 9044            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9045        let target_column = target_display_point.column() as usize;
 9046
 9047        let target_x = line_layout.x_for_index(target_column);
 9048        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9049            - scroll_pixel_position.y;
 9050
 9051        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9052
 9053        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9054        border_color.l += 0.001;
 9055
 9056        let mut element = v_flex()
 9057            .items_end()
 9058            .when(flag_on_right, |el| el.items_start())
 9059            .child(if flag_on_right {
 9060                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9061                    .rounded_bl(px(0.))
 9062                    .rounded_tl(px(0.))
 9063                    .border_l_2()
 9064                    .border_color(border_color)
 9065            } else {
 9066                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9067                    .rounded_br(px(0.))
 9068                    .rounded_tr(px(0.))
 9069                    .border_r_2()
 9070                    .border_color(border_color)
 9071            })
 9072            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9073            .into_any();
 9074
 9075        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9076
 9077        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9078            - point(
 9079                if flag_on_right {
 9080                    POLE_WIDTH
 9081                } else {
 9082                    size.width - POLE_WIDTH
 9083                },
 9084                size.height - line_height,
 9085            );
 9086
 9087        origin.x = origin.x.max(content_origin.x);
 9088
 9089        element.prepaint_at(origin, window, cx);
 9090
 9091        Some((element, origin))
 9092    }
 9093
 9094    fn render_edit_prediction_scroll_popover(
 9095        &mut self,
 9096        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9097        scroll_icon: IconName,
 9098        visible_row_range: Range<DisplayRow>,
 9099        line_layouts: &[LineWithInvisibles],
 9100        newest_selection_head: Option<DisplayPoint>,
 9101        scrolled_content_origin: gpui::Point<Pixels>,
 9102        window: &mut Window,
 9103        cx: &mut App,
 9104    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9105        let mut element = self
 9106            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9107            .into_any();
 9108
 9109        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9110
 9111        let cursor = newest_selection_head?;
 9112        let cursor_row_layout =
 9113            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9114        let cursor_column = cursor.column() as usize;
 9115
 9116        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9117
 9118        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9119
 9120        element.prepaint_at(origin, window, cx);
 9121        Some((element, origin))
 9122    }
 9123
 9124    fn render_edit_prediction_eager_jump_popover(
 9125        &mut self,
 9126        text_bounds: &Bounds<Pixels>,
 9127        content_origin: gpui::Point<Pixels>,
 9128        editor_snapshot: &EditorSnapshot,
 9129        visible_row_range: Range<DisplayRow>,
 9130        scroll_top: ScrollOffset,
 9131        scroll_bottom: ScrollOffset,
 9132        line_height: Pixels,
 9133        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9134        target_display_point: DisplayPoint,
 9135        editor_width: Pixels,
 9136        window: &mut Window,
 9137        cx: &mut App,
 9138    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9139        if target_display_point.row().as_f64() < scroll_top {
 9140            let mut element = self
 9141                .render_edit_prediction_line_popover(
 9142                    "Jump to Edit",
 9143                    Some(IconName::ArrowUp),
 9144                    window,
 9145                    cx,
 9146                )
 9147                .into_any();
 9148
 9149            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9150            let offset = point(
 9151                (text_bounds.size.width - size.width) / 2.,
 9152                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9153            );
 9154
 9155            let origin = text_bounds.origin + offset;
 9156            element.prepaint_at(origin, window, cx);
 9157            Some((element, origin))
 9158        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9159            let mut element = self
 9160                .render_edit_prediction_line_popover(
 9161                    "Jump to Edit",
 9162                    Some(IconName::ArrowDown),
 9163                    window,
 9164                    cx,
 9165                )
 9166                .into_any();
 9167
 9168            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9169            let offset = point(
 9170                (text_bounds.size.width - size.width) / 2.,
 9171                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9172            );
 9173
 9174            let origin = text_bounds.origin + offset;
 9175            element.prepaint_at(origin, window, cx);
 9176            Some((element, origin))
 9177        } else {
 9178            self.render_edit_prediction_end_of_line_popover(
 9179                "Jump to Edit",
 9180                editor_snapshot,
 9181                visible_row_range,
 9182                target_display_point,
 9183                line_height,
 9184                scroll_pixel_position,
 9185                content_origin,
 9186                editor_width,
 9187                window,
 9188                cx,
 9189            )
 9190        }
 9191    }
 9192
 9193    fn render_edit_prediction_end_of_line_popover(
 9194        self: &mut Editor,
 9195        label: &'static str,
 9196        editor_snapshot: &EditorSnapshot,
 9197        visible_row_range: Range<DisplayRow>,
 9198        target_display_point: DisplayPoint,
 9199        line_height: Pixels,
 9200        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9201        content_origin: gpui::Point<Pixels>,
 9202        editor_width: Pixels,
 9203        window: &mut Window,
 9204        cx: &mut App,
 9205    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9206        let target_line_end = DisplayPoint::new(
 9207            target_display_point.row(),
 9208            editor_snapshot.line_len(target_display_point.row()),
 9209        );
 9210
 9211        let mut element = self
 9212            .render_edit_prediction_line_popover(label, None, window, cx)
 9213            .into_any();
 9214
 9215        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9216
 9217        let line_origin =
 9218            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9219
 9220        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9221        let mut origin = start_point
 9222            + line_origin
 9223            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9224        origin.x = origin.x.max(content_origin.x);
 9225
 9226        let max_x = content_origin.x + editor_width - size.width;
 9227
 9228        if origin.x > max_x {
 9229            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9230
 9231            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9232                origin.y += offset;
 9233                IconName::ArrowUp
 9234            } else {
 9235                origin.y -= offset;
 9236                IconName::ArrowDown
 9237            };
 9238
 9239            element = self
 9240                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9241                .into_any();
 9242
 9243            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9244
 9245            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9246        }
 9247
 9248        element.prepaint_at(origin, window, cx);
 9249        Some((element, origin))
 9250    }
 9251
 9252    fn render_edit_prediction_diff_popover(
 9253        self: &Editor,
 9254        text_bounds: &Bounds<Pixels>,
 9255        content_origin: gpui::Point<Pixels>,
 9256        right_margin: Pixels,
 9257        editor_snapshot: &EditorSnapshot,
 9258        visible_row_range: Range<DisplayRow>,
 9259        line_layouts: &[LineWithInvisibles],
 9260        line_height: Pixels,
 9261        scroll_position: gpui::Point<ScrollOffset>,
 9262        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9263        newest_selection_head: Option<DisplayPoint>,
 9264        editor_width: Pixels,
 9265        style: &EditorStyle,
 9266        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9267        edit_preview: &Option<language::EditPreview>,
 9268        snapshot: &language::BufferSnapshot,
 9269        window: &mut Window,
 9270        cx: &mut App,
 9271    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9272        let edit_start = edits
 9273            .first()
 9274            .unwrap()
 9275            .0
 9276            .start
 9277            .to_display_point(editor_snapshot);
 9278        let edit_end = edits
 9279            .last()
 9280            .unwrap()
 9281            .0
 9282            .end
 9283            .to_display_point(editor_snapshot);
 9284
 9285        let is_visible = visible_row_range.contains(&edit_start.row())
 9286            || visible_row_range.contains(&edit_end.row());
 9287        if !is_visible {
 9288            return None;
 9289        }
 9290
 9291        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9292            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9293        } else {
 9294            // Fallback for providers without edit_preview
 9295            crate::edit_prediction_fallback_text(edits, cx)
 9296        };
 9297
 9298        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9299        let line_count = highlighted_edits.text.lines().count();
 9300
 9301        const BORDER_WIDTH: Pixels = px(1.);
 9302
 9303        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9304        let has_keybind = keybind.is_some();
 9305
 9306        let mut element = h_flex()
 9307            .items_start()
 9308            .child(
 9309                h_flex()
 9310                    .bg(cx.theme().colors().editor_background)
 9311                    .border(BORDER_WIDTH)
 9312                    .shadow_xs()
 9313                    .border_color(cx.theme().colors().border)
 9314                    .rounded_l_lg()
 9315                    .when(line_count > 1, |el| el.rounded_br_lg())
 9316                    .pr_1()
 9317                    .child(styled_text),
 9318            )
 9319            .child(
 9320                h_flex()
 9321                    .h(line_height + BORDER_WIDTH * 2.)
 9322                    .px_1p5()
 9323                    .gap_1()
 9324                    // Workaround: For some reason, there's a gap if we don't do this
 9325                    .ml(-BORDER_WIDTH)
 9326                    .shadow(vec![gpui::BoxShadow {
 9327                        color: gpui::black().opacity(0.05),
 9328                        offset: point(px(1.), px(1.)),
 9329                        blur_radius: px(2.),
 9330                        spread_radius: px(0.),
 9331                    }])
 9332                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9333                    .border(BORDER_WIDTH)
 9334                    .border_color(cx.theme().colors().border)
 9335                    .rounded_r_lg()
 9336                    .id("edit_prediction_diff_popover_keybind")
 9337                    .when(!has_keybind, |el| {
 9338                        let status_colors = cx.theme().status();
 9339
 9340                        el.bg(status_colors.error_background)
 9341                            .border_color(status_colors.error.opacity(0.6))
 9342                            .child(Icon::new(IconName::Info).color(Color::Error))
 9343                            .cursor_default()
 9344                            .hoverable_tooltip(move |_window, cx| {
 9345                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9346                            })
 9347                    })
 9348                    .children(keybind),
 9349            )
 9350            .into_any();
 9351
 9352        let longest_row =
 9353            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9354        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9355            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9356        } else {
 9357            layout_line(
 9358                longest_row,
 9359                editor_snapshot,
 9360                style,
 9361                editor_width,
 9362                |_| false,
 9363                window,
 9364                cx,
 9365            )
 9366            .width
 9367        };
 9368
 9369        let viewport_bounds =
 9370            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9371                right: -right_margin,
 9372                ..Default::default()
 9373            });
 9374
 9375        let x_after_longest = Pixels::from(
 9376            ScrollPixelOffset::from(
 9377                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9378            ) - scroll_pixel_position.x,
 9379        );
 9380
 9381        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9382
 9383        // Fully visible if it can be displayed within the window (allow overlapping other
 9384        // panes). However, this is only allowed if the popover starts within text_bounds.
 9385        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9386            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9387
 9388        let mut origin = if can_position_to_the_right {
 9389            point(
 9390                x_after_longest,
 9391                text_bounds.origin.y
 9392                    + Pixels::from(
 9393                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9394                            - scroll_pixel_position.y,
 9395                    ),
 9396            )
 9397        } else {
 9398            let cursor_row = newest_selection_head.map(|head| head.row());
 9399            let above_edit = edit_start
 9400                .row()
 9401                .0
 9402                .checked_sub(line_count as u32)
 9403                .map(DisplayRow);
 9404            let below_edit = Some(edit_end.row() + 1);
 9405            let above_cursor =
 9406                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9407            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9408
 9409            // Place the edit popover adjacent to the edit if there is a location
 9410            // available that is onscreen and does not obscure the cursor. Otherwise,
 9411            // place it adjacent to the cursor.
 9412            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9413                .into_iter()
 9414                .flatten()
 9415                .find(|&start_row| {
 9416                    let end_row = start_row + line_count as u32;
 9417                    visible_row_range.contains(&start_row)
 9418                        && visible_row_range.contains(&end_row)
 9419                        && cursor_row
 9420                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9421                })?;
 9422
 9423            content_origin
 9424                + point(
 9425                    Pixels::from(-scroll_pixel_position.x),
 9426                    Pixels::from(
 9427                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9428                    ),
 9429                )
 9430        };
 9431
 9432        origin.x -= BORDER_WIDTH;
 9433
 9434        window.defer_draw(element, origin, 1);
 9435
 9436        // Do not return an element, since it will already be drawn due to defer_draw.
 9437        None
 9438    }
 9439
 9440    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9441        px(30.)
 9442    }
 9443
 9444    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9445        if self.read_only(cx) {
 9446            cx.theme().players().read_only()
 9447        } else {
 9448            self.style.as_ref().unwrap().local_player
 9449        }
 9450    }
 9451
 9452    fn render_edit_prediction_accept_keybind(
 9453        &self,
 9454        window: &mut Window,
 9455        cx: &mut App,
 9456    ) -> Option<AnyElement> {
 9457        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9458        let accept_keystroke = accept_binding.keystroke()?;
 9459
 9460        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9461
 9462        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9463            Color::Accent
 9464        } else {
 9465            Color::Muted
 9466        };
 9467
 9468        h_flex()
 9469            .px_0p5()
 9470            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9471            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9472            .text_size(TextSize::XSmall.rems(cx))
 9473            .child(h_flex().children(ui::render_modifiers(
 9474                accept_keystroke.modifiers(),
 9475                PlatformStyle::platform(),
 9476                Some(modifiers_color),
 9477                Some(IconSize::XSmall.rems().into()),
 9478                true,
 9479            )))
 9480            .when(is_platform_style_mac, |parent| {
 9481                parent.child(accept_keystroke.key().to_string())
 9482            })
 9483            .when(!is_platform_style_mac, |parent| {
 9484                parent.child(
 9485                    Key::new(
 9486                        util::capitalize(accept_keystroke.key()),
 9487                        Some(Color::Default),
 9488                    )
 9489                    .size(Some(IconSize::XSmall.rems().into())),
 9490                )
 9491            })
 9492            .into_any()
 9493            .into()
 9494    }
 9495
 9496    fn render_edit_prediction_line_popover(
 9497        &self,
 9498        label: impl Into<SharedString>,
 9499        icon: Option<IconName>,
 9500        window: &mut Window,
 9501        cx: &mut App,
 9502    ) -> Stateful<Div> {
 9503        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9504
 9505        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9506        let has_keybind = keybind.is_some();
 9507
 9508        h_flex()
 9509            .id("ep-line-popover")
 9510            .py_0p5()
 9511            .pl_1()
 9512            .pr(padding_right)
 9513            .gap_1()
 9514            .rounded_md()
 9515            .border_1()
 9516            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9517            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9518            .shadow_xs()
 9519            .when(!has_keybind, |el| {
 9520                let status_colors = cx.theme().status();
 9521
 9522                el.bg(status_colors.error_background)
 9523                    .border_color(status_colors.error.opacity(0.6))
 9524                    .pl_2()
 9525                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9526                    .cursor_default()
 9527                    .hoverable_tooltip(move |_window, cx| {
 9528                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9529                    })
 9530            })
 9531            .children(keybind)
 9532            .child(
 9533                Label::new(label)
 9534                    .size(LabelSize::Small)
 9535                    .when(!has_keybind, |el| {
 9536                        el.color(cx.theme().status().error.into()).strikethrough()
 9537                    }),
 9538            )
 9539            .when(!has_keybind, |el| {
 9540                el.child(
 9541                    h_flex().ml_1().child(
 9542                        Icon::new(IconName::Info)
 9543                            .size(IconSize::Small)
 9544                            .color(cx.theme().status().error.into()),
 9545                    ),
 9546                )
 9547            })
 9548            .when_some(icon, |element, icon| {
 9549                element.child(
 9550                    div()
 9551                        .mt(px(1.5))
 9552                        .child(Icon::new(icon).size(IconSize::Small)),
 9553                )
 9554            })
 9555    }
 9556
 9557    fn render_edit_prediction_jump_outside_popover(
 9558        &self,
 9559        snapshot: &BufferSnapshot,
 9560        window: &mut Window,
 9561        cx: &mut App,
 9562    ) -> Stateful<Div> {
 9563        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9564        let has_keybind = keybind.is_some();
 9565
 9566        let file_name = snapshot
 9567            .file()
 9568            .map(|file| SharedString::new(file.file_name(cx)))
 9569            .unwrap_or(SharedString::new_static("untitled"));
 9570
 9571        h_flex()
 9572            .id("ep-jump-outside-popover")
 9573            .py_1()
 9574            .px_2()
 9575            .gap_1()
 9576            .rounded_md()
 9577            .border_1()
 9578            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9579            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9580            .shadow_xs()
 9581            .when(!has_keybind, |el| {
 9582                let status_colors = cx.theme().status();
 9583
 9584                el.bg(status_colors.error_background)
 9585                    .border_color(status_colors.error.opacity(0.6))
 9586                    .pl_2()
 9587                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9588                    .cursor_default()
 9589                    .hoverable_tooltip(move |_window, cx| {
 9590                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9591                    })
 9592            })
 9593            .children(keybind)
 9594            .child(
 9595                Label::new(file_name)
 9596                    .size(LabelSize::Small)
 9597                    .buffer_font(cx)
 9598                    .when(!has_keybind, |el| {
 9599                        el.color(cx.theme().status().error.into()).strikethrough()
 9600                    }),
 9601            )
 9602            .when(!has_keybind, |el| {
 9603                el.child(
 9604                    h_flex().ml_1().child(
 9605                        Icon::new(IconName::Info)
 9606                            .size(IconSize::Small)
 9607                            .color(cx.theme().status().error.into()),
 9608                    ),
 9609                )
 9610            })
 9611            .child(
 9612                div()
 9613                    .mt(px(1.5))
 9614                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9615            )
 9616    }
 9617
 9618    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9619        let accent_color = cx.theme().colors().text_accent;
 9620        let editor_bg_color = cx.theme().colors().editor_background;
 9621        editor_bg_color.blend(accent_color.opacity(0.1))
 9622    }
 9623
 9624    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9625        let accent_color = cx.theme().colors().text_accent;
 9626        let editor_bg_color = cx.theme().colors().editor_background;
 9627        editor_bg_color.blend(accent_color.opacity(0.6))
 9628    }
 9629    fn get_prediction_provider_icon_name(
 9630        provider: &Option<RegisteredEditPredictionDelegate>,
 9631    ) -> IconName {
 9632        match provider {
 9633            Some(provider) => match provider.provider.name() {
 9634                "copilot" => IconName::Copilot,
 9635                "supermaven" => IconName::Supermaven,
 9636                _ => IconName::ZedPredict,
 9637            },
 9638            None => IconName::ZedPredict,
 9639        }
 9640    }
 9641
 9642    fn render_edit_prediction_cursor_popover(
 9643        &self,
 9644        min_width: Pixels,
 9645        max_width: Pixels,
 9646        cursor_point: Point,
 9647        style: &EditorStyle,
 9648        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9649        _window: &Window,
 9650        cx: &mut Context<Editor>,
 9651    ) -> Option<AnyElement> {
 9652        let provider = self.edit_prediction_provider.as_ref()?;
 9653        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9654
 9655        let is_refreshing = provider.provider.is_refreshing(cx);
 9656
 9657        fn pending_completion_container(icon: IconName) -> Div {
 9658            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9659        }
 9660
 9661        let completion = match &self.active_edit_prediction {
 9662            Some(prediction) => {
 9663                if !self.has_visible_completions_menu() {
 9664                    const RADIUS: Pixels = px(6.);
 9665                    const BORDER_WIDTH: Pixels = px(1.);
 9666
 9667                    return Some(
 9668                        h_flex()
 9669                            .elevation_2(cx)
 9670                            .border(BORDER_WIDTH)
 9671                            .border_color(cx.theme().colors().border)
 9672                            .when(accept_keystroke.is_none(), |el| {
 9673                                el.border_color(cx.theme().status().error)
 9674                            })
 9675                            .rounded(RADIUS)
 9676                            .rounded_tl(px(0.))
 9677                            .overflow_hidden()
 9678                            .child(div().px_1p5().child(match &prediction.completion {
 9679                                EditPrediction::MoveWithin { target, snapshot } => {
 9680                                    use text::ToPoint as _;
 9681                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9682                                    {
 9683                                        Icon::new(IconName::ZedPredictDown)
 9684                                    } else {
 9685                                        Icon::new(IconName::ZedPredictUp)
 9686                                    }
 9687                                }
 9688                                EditPrediction::MoveOutside { .. } => {
 9689                                    // TODO [zeta2] custom icon for external jump?
 9690                                    Icon::new(provider_icon)
 9691                                }
 9692                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9693                            }))
 9694                            .child(
 9695                                h_flex()
 9696                                    .gap_1()
 9697                                    .py_1()
 9698                                    .px_2()
 9699                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9700                                    .border_l_1()
 9701                                    .border_color(cx.theme().colors().border)
 9702                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9703                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9704                                        el.child(
 9705                                            Label::new("Hold")
 9706                                                .size(LabelSize::Small)
 9707                                                .when(accept_keystroke.is_none(), |el| {
 9708                                                    el.strikethrough()
 9709                                                })
 9710                                                .line_height_style(LineHeightStyle::UiLabel),
 9711                                        )
 9712                                    })
 9713                                    .id("edit_prediction_cursor_popover_keybind")
 9714                                    .when(accept_keystroke.is_none(), |el| {
 9715                                        let status_colors = cx.theme().status();
 9716
 9717                                        el.bg(status_colors.error_background)
 9718                                            .border_color(status_colors.error.opacity(0.6))
 9719                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9720                                            .cursor_default()
 9721                                            .hoverable_tooltip(move |_window, cx| {
 9722                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9723                                                    .into()
 9724                                            })
 9725                                    })
 9726                                    .when_some(
 9727                                        accept_keystroke.as_ref(),
 9728                                        |el, accept_keystroke| {
 9729                                            el.child(h_flex().children(ui::render_modifiers(
 9730                                                accept_keystroke.modifiers(),
 9731                                                PlatformStyle::platform(),
 9732                                                Some(Color::Default),
 9733                                                Some(IconSize::XSmall.rems().into()),
 9734                                                false,
 9735                                            )))
 9736                                        },
 9737                                    ),
 9738                            )
 9739                            .into_any(),
 9740                    );
 9741                }
 9742
 9743                self.render_edit_prediction_cursor_popover_preview(
 9744                    prediction,
 9745                    cursor_point,
 9746                    style,
 9747                    cx,
 9748                )?
 9749            }
 9750
 9751            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9752                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9753                    stale_completion,
 9754                    cursor_point,
 9755                    style,
 9756                    cx,
 9757                )?,
 9758
 9759                None => pending_completion_container(provider_icon)
 9760                    .child(Label::new("...").size(LabelSize::Small)),
 9761            },
 9762
 9763            None => pending_completion_container(provider_icon)
 9764                .child(Label::new("...").size(LabelSize::Small)),
 9765        };
 9766
 9767        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9768            completion
 9769                .with_animation(
 9770                    "loading-completion",
 9771                    Animation::new(Duration::from_secs(2))
 9772                        .repeat()
 9773                        .with_easing(pulsating_between(0.4, 0.8)),
 9774                    |label, delta| label.opacity(delta),
 9775                )
 9776                .into_any_element()
 9777        } else {
 9778            completion.into_any_element()
 9779        };
 9780
 9781        let has_completion = self.active_edit_prediction.is_some();
 9782
 9783        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9784        Some(
 9785            h_flex()
 9786                .min_w(min_width)
 9787                .max_w(max_width)
 9788                .flex_1()
 9789                .elevation_2(cx)
 9790                .border_color(cx.theme().colors().border)
 9791                .child(
 9792                    div()
 9793                        .flex_1()
 9794                        .py_1()
 9795                        .px_2()
 9796                        .overflow_hidden()
 9797                        .child(completion),
 9798                )
 9799                .when_some(accept_keystroke, |el, accept_keystroke| {
 9800                    if !accept_keystroke.modifiers().modified() {
 9801                        return el;
 9802                    }
 9803
 9804                    el.child(
 9805                        h_flex()
 9806                            .h_full()
 9807                            .border_l_1()
 9808                            .rounded_r_lg()
 9809                            .border_color(cx.theme().colors().border)
 9810                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9811                            .gap_1()
 9812                            .py_1()
 9813                            .px_2()
 9814                            .child(
 9815                                h_flex()
 9816                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9817                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9818                                    .child(h_flex().children(ui::render_modifiers(
 9819                                        accept_keystroke.modifiers(),
 9820                                        PlatformStyle::platform(),
 9821                                        Some(if !has_completion {
 9822                                            Color::Muted
 9823                                        } else {
 9824                                            Color::Default
 9825                                        }),
 9826                                        None,
 9827                                        false,
 9828                                    ))),
 9829                            )
 9830                            .child(Label::new("Preview").into_any_element())
 9831                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9832                    )
 9833                })
 9834                .into_any(),
 9835        )
 9836    }
 9837
 9838    fn render_edit_prediction_cursor_popover_preview(
 9839        &self,
 9840        completion: &EditPredictionState,
 9841        cursor_point: Point,
 9842        style: &EditorStyle,
 9843        cx: &mut Context<Editor>,
 9844    ) -> Option<Div> {
 9845        use text::ToPoint as _;
 9846
 9847        fn render_relative_row_jump(
 9848            prefix: impl Into<String>,
 9849            current_row: u32,
 9850            target_row: u32,
 9851        ) -> Div {
 9852            let (row_diff, arrow) = if target_row < current_row {
 9853                (current_row - target_row, IconName::ArrowUp)
 9854            } else {
 9855                (target_row - current_row, IconName::ArrowDown)
 9856            };
 9857
 9858            h_flex()
 9859                .child(
 9860                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9861                        .color(Color::Muted)
 9862                        .size(LabelSize::Small),
 9863                )
 9864                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9865        }
 9866
 9867        let supports_jump = self
 9868            .edit_prediction_provider
 9869            .as_ref()
 9870            .map(|provider| provider.provider.supports_jump_to_edit())
 9871            .unwrap_or(true);
 9872
 9873        match &completion.completion {
 9874            EditPrediction::MoveWithin {
 9875                target, snapshot, ..
 9876            } => {
 9877                if !supports_jump {
 9878                    return None;
 9879                }
 9880
 9881                Some(
 9882                    h_flex()
 9883                        .px_2()
 9884                        .gap_2()
 9885                        .flex_1()
 9886                        .child(
 9887                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9888                                Icon::new(IconName::ZedPredictDown)
 9889                            } else {
 9890                                Icon::new(IconName::ZedPredictUp)
 9891                            },
 9892                        )
 9893                        .child(Label::new("Jump to Edit")),
 9894                )
 9895            }
 9896            EditPrediction::MoveOutside { snapshot, .. } => {
 9897                let file_name = snapshot
 9898                    .file()
 9899                    .map(|file| file.file_name(cx))
 9900                    .unwrap_or("untitled");
 9901                Some(
 9902                    h_flex()
 9903                        .px_2()
 9904                        .gap_2()
 9905                        .flex_1()
 9906                        .child(Icon::new(IconName::ZedPredict))
 9907                        .child(Label::new(format!("Jump to {file_name}"))),
 9908                )
 9909            }
 9910            EditPrediction::Edit {
 9911                edits,
 9912                edit_preview,
 9913                snapshot,
 9914                display_mode: _,
 9915            } => {
 9916                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9917
 9918                let (highlighted_edits, has_more_lines) =
 9919                    if let Some(edit_preview) = edit_preview.as_ref() {
 9920                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9921                            .first_line_preview()
 9922                    } else {
 9923                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9924                    };
 9925
 9926                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9927                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9928
 9929                let preview = h_flex()
 9930                    .gap_1()
 9931                    .min_w_16()
 9932                    .child(styled_text)
 9933                    .when(has_more_lines, |parent| parent.child(""));
 9934
 9935                let left = if supports_jump && first_edit_row != cursor_point.row {
 9936                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9937                        .into_any_element()
 9938                } else {
 9939                    let icon_name =
 9940                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9941                    Icon::new(icon_name).into_any_element()
 9942                };
 9943
 9944                Some(
 9945                    h_flex()
 9946                        .h_full()
 9947                        .flex_1()
 9948                        .gap_2()
 9949                        .pr_1()
 9950                        .overflow_x_hidden()
 9951                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9952                        .child(left)
 9953                        .child(preview),
 9954                )
 9955            }
 9956        }
 9957    }
 9958
 9959    pub fn render_context_menu(
 9960        &mut self,
 9961        max_height_in_lines: u32,
 9962        window: &mut Window,
 9963        cx: &mut Context<Editor>,
 9964    ) -> Option<AnyElement> {
 9965        let menu = self.context_menu.borrow();
 9966        let menu = menu.as_ref()?;
 9967        if !menu.visible() {
 9968            return None;
 9969        };
 9970        self.style
 9971            .as_ref()
 9972            .map(|style| menu.render(style, max_height_in_lines, window, cx))
 9973    }
 9974
 9975    fn render_context_menu_aside(
 9976        &mut self,
 9977        max_size: Size<Pixels>,
 9978        window: &mut Window,
 9979        cx: &mut Context<Editor>,
 9980    ) -> Option<AnyElement> {
 9981        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9982            if menu.visible() {
 9983                menu.render_aside(max_size, window, cx)
 9984            } else {
 9985                None
 9986            }
 9987        })
 9988    }
 9989
 9990    fn hide_context_menu(
 9991        &mut self,
 9992        window: &mut Window,
 9993        cx: &mut Context<Self>,
 9994    ) -> Option<CodeContextMenu> {
 9995        cx.notify();
 9996        self.completion_tasks.clear();
 9997        let context_menu = self.context_menu.borrow_mut().take();
 9998        self.stale_edit_prediction_in_menu.take();
 9999        self.update_visible_edit_prediction(window, cx);
10000        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10001            && let Some(completion_provider) = &self.completion_provider
10002        {
10003            completion_provider.selection_changed(None, window, cx);
10004        }
10005        context_menu
10006    }
10007
10008    fn show_snippet_choices(
10009        &mut self,
10010        choices: &Vec<String>,
10011        selection: Range<Anchor>,
10012        cx: &mut Context<Self>,
10013    ) {
10014        let Some((_, buffer, _)) = self
10015            .buffer()
10016            .read(cx)
10017            .excerpt_containing(selection.start, cx)
10018        else {
10019            return;
10020        };
10021        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10022        else {
10023            return;
10024        };
10025        if buffer != end_buffer {
10026            log::error!("expected anchor range to have matching buffer IDs");
10027            return;
10028        }
10029
10030        let id = post_inc(&mut self.next_completion_id);
10031        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10032        let mut context_menu = self.context_menu.borrow_mut();
10033        let old_menu = context_menu.take();
10034        *context_menu = Some(CodeContextMenu::Completions(
10035            CompletionsMenu::new_snippet_choices(
10036                id,
10037                true,
10038                choices,
10039                selection,
10040                buffer,
10041                old_menu.map(|menu| menu.primary_scroll_handle()),
10042                snippet_sort_order,
10043            ),
10044        ));
10045    }
10046
10047    pub fn insert_snippet(
10048        &mut self,
10049        insertion_ranges: &[Range<MultiBufferOffset>],
10050        snippet: Snippet,
10051        window: &mut Window,
10052        cx: &mut Context<Self>,
10053    ) -> Result<()> {
10054        struct Tabstop<T> {
10055            is_end_tabstop: bool,
10056            ranges: Vec<Range<T>>,
10057            choices: Option<Vec<String>>,
10058        }
10059
10060        let tabstops = self.buffer.update(cx, |buffer, cx| {
10061            let snippet_text: Arc<str> = snippet.text.clone().into();
10062            let edits = insertion_ranges
10063                .iter()
10064                .cloned()
10065                .map(|range| (range, snippet_text.clone()));
10066            let autoindent_mode = AutoindentMode::Block {
10067                original_indent_columns: Vec::new(),
10068            };
10069            buffer.edit(edits, Some(autoindent_mode), cx);
10070
10071            let snapshot = &*buffer.read(cx);
10072            let snippet = &snippet;
10073            snippet
10074                .tabstops
10075                .iter()
10076                .map(|tabstop| {
10077                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10078                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10079                    });
10080                    let mut tabstop_ranges = tabstop
10081                        .ranges
10082                        .iter()
10083                        .flat_map(|tabstop_range| {
10084                            let mut delta = 0_isize;
10085                            insertion_ranges.iter().map(move |insertion_range| {
10086                                let insertion_start = insertion_range.start + delta;
10087                                delta += snippet.text.len() as isize
10088                                    - (insertion_range.end - insertion_range.start) as isize;
10089
10090                                let start =
10091                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10092                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10093                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10094                            })
10095                        })
10096                        .collect::<Vec<_>>();
10097                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10098
10099                    Tabstop {
10100                        is_end_tabstop,
10101                        ranges: tabstop_ranges,
10102                        choices: tabstop.choices.clone(),
10103                    }
10104                })
10105                .collect::<Vec<_>>()
10106        });
10107        if let Some(tabstop) = tabstops.first() {
10108            self.change_selections(Default::default(), window, cx, |s| {
10109                // Reverse order so that the first range is the newest created selection.
10110                // Completions will use it and autoscroll will prioritize it.
10111                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10112            });
10113
10114            if let Some(choices) = &tabstop.choices
10115                && let Some(selection) = tabstop.ranges.first()
10116            {
10117                self.show_snippet_choices(choices, selection.clone(), cx)
10118            }
10119
10120            // If we're already at the last tabstop and it's at the end of the snippet,
10121            // we're done, we don't need to keep the state around.
10122            if !tabstop.is_end_tabstop {
10123                let choices = tabstops
10124                    .iter()
10125                    .map(|tabstop| tabstop.choices.clone())
10126                    .collect();
10127
10128                let ranges = tabstops
10129                    .into_iter()
10130                    .map(|tabstop| tabstop.ranges)
10131                    .collect::<Vec<_>>();
10132
10133                self.snippet_stack.push(SnippetState {
10134                    active_index: 0,
10135                    ranges,
10136                    choices,
10137                });
10138            }
10139
10140            // Check whether the just-entered snippet ends with an auto-closable bracket.
10141            if self.autoclose_regions.is_empty() {
10142                let snapshot = self.buffer.read(cx).snapshot(cx);
10143                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10144                    let selection_head = selection.head();
10145                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10146                        continue;
10147                    };
10148
10149                    let mut bracket_pair = None;
10150                    let max_lookup_length = scope
10151                        .brackets()
10152                        .map(|(pair, _)| {
10153                            pair.start
10154                                .as_str()
10155                                .chars()
10156                                .count()
10157                                .max(pair.end.as_str().chars().count())
10158                        })
10159                        .max();
10160                    if let Some(max_lookup_length) = max_lookup_length {
10161                        let next_text = snapshot
10162                            .chars_at(selection_head)
10163                            .take(max_lookup_length)
10164                            .collect::<String>();
10165                        let prev_text = snapshot
10166                            .reversed_chars_at(selection_head)
10167                            .take(max_lookup_length)
10168                            .collect::<String>();
10169
10170                        for (pair, enabled) in scope.brackets() {
10171                            if enabled
10172                                && pair.close
10173                                && prev_text.starts_with(pair.start.as_str())
10174                                && next_text.starts_with(pair.end.as_str())
10175                            {
10176                                bracket_pair = Some(pair.clone());
10177                                break;
10178                            }
10179                        }
10180                    }
10181
10182                    if let Some(pair) = bracket_pair {
10183                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10184                        let autoclose_enabled =
10185                            self.use_autoclose && snapshot_settings.use_autoclose;
10186                        if autoclose_enabled {
10187                            let start = snapshot.anchor_after(selection_head);
10188                            let end = snapshot.anchor_after(selection_head);
10189                            self.autoclose_regions.push(AutocloseRegion {
10190                                selection_id: selection.id,
10191                                range: start..end,
10192                                pair,
10193                            });
10194                        }
10195                    }
10196                }
10197            }
10198        }
10199        Ok(())
10200    }
10201
10202    pub fn move_to_next_snippet_tabstop(
10203        &mut self,
10204        window: &mut Window,
10205        cx: &mut Context<Self>,
10206    ) -> bool {
10207        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10208    }
10209
10210    pub fn move_to_prev_snippet_tabstop(
10211        &mut self,
10212        window: &mut Window,
10213        cx: &mut Context<Self>,
10214    ) -> bool {
10215        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10216    }
10217
10218    pub fn move_to_snippet_tabstop(
10219        &mut self,
10220        bias: Bias,
10221        window: &mut Window,
10222        cx: &mut Context<Self>,
10223    ) -> bool {
10224        if let Some(mut snippet) = self.snippet_stack.pop() {
10225            match bias {
10226                Bias::Left => {
10227                    if snippet.active_index > 0 {
10228                        snippet.active_index -= 1;
10229                    } else {
10230                        self.snippet_stack.push(snippet);
10231                        return false;
10232                    }
10233                }
10234                Bias::Right => {
10235                    if snippet.active_index + 1 < snippet.ranges.len() {
10236                        snippet.active_index += 1;
10237                    } else {
10238                        self.snippet_stack.push(snippet);
10239                        return false;
10240                    }
10241                }
10242            }
10243            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10244                self.change_selections(Default::default(), window, cx, |s| {
10245                    // Reverse order so that the first range is the newest created selection.
10246                    // Completions will use it and autoscroll will prioritize it.
10247                    s.select_ranges(current_ranges.iter().rev().cloned())
10248                });
10249
10250                if let Some(choices) = &snippet.choices[snippet.active_index]
10251                    && let Some(selection) = current_ranges.first()
10252                {
10253                    self.show_snippet_choices(choices, selection.clone(), cx);
10254                }
10255
10256                // If snippet state is not at the last tabstop, push it back on the stack
10257                if snippet.active_index + 1 < snippet.ranges.len() {
10258                    self.snippet_stack.push(snippet);
10259                }
10260                return true;
10261            }
10262        }
10263
10264        false
10265    }
10266
10267    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10268        self.transact(window, cx, |this, window, cx| {
10269            this.select_all(&SelectAll, window, cx);
10270            this.insert("", window, cx);
10271        });
10272    }
10273
10274    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10275        if self.read_only(cx) {
10276            return;
10277        }
10278        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10279        self.transact(window, cx, |this, window, cx| {
10280            this.select_autoclose_pair(window, cx);
10281
10282            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10283
10284            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10285            if !this.linked_edit_ranges.is_empty() {
10286                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10287                let snapshot = this.buffer.read(cx).snapshot(cx);
10288
10289                for selection in selections.iter() {
10290                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10291                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10292                    if selection_start.buffer_id != selection_end.buffer_id {
10293                        continue;
10294                    }
10295                    if let Some(ranges) =
10296                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10297                    {
10298                        for (buffer, entries) in ranges {
10299                            linked_ranges.entry(buffer).or_default().extend(entries);
10300                        }
10301                    }
10302                }
10303            }
10304
10305            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10306            for selection in &mut selections {
10307                if selection.is_empty() {
10308                    let old_head = selection.head();
10309                    let mut new_head =
10310                        movement::left(&display_map, old_head.to_display_point(&display_map))
10311                            .to_point(&display_map);
10312                    if let Some((buffer, line_buffer_range)) = display_map
10313                        .buffer_snapshot()
10314                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10315                    {
10316                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10317                        let indent_len = match indent_size.kind {
10318                            IndentKind::Space => {
10319                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10320                            }
10321                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10322                        };
10323                        if old_head.column <= indent_size.len && old_head.column > 0 {
10324                            let indent_len = indent_len.get();
10325                            new_head = cmp::min(
10326                                new_head,
10327                                MultiBufferPoint::new(
10328                                    old_head.row,
10329                                    ((old_head.column - 1) / indent_len) * indent_len,
10330                                ),
10331                            );
10332                        }
10333                    }
10334
10335                    selection.set_head(new_head, SelectionGoal::None);
10336                }
10337            }
10338
10339            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10340            this.insert("", window, cx);
10341            let empty_str: Arc<str> = Arc::from("");
10342            for (buffer, edits) in linked_ranges {
10343                let snapshot = buffer.read(cx).snapshot();
10344                use text::ToPoint as TP;
10345
10346                let edits = edits
10347                    .into_iter()
10348                    .map(|range| {
10349                        let end_point = TP::to_point(&range.end, &snapshot);
10350                        let mut start_point = TP::to_point(&range.start, &snapshot);
10351
10352                        if end_point == start_point {
10353                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10354                                .saturating_sub(1);
10355                            start_point =
10356                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10357                        };
10358
10359                        (start_point..end_point, empty_str.clone())
10360                    })
10361                    .sorted_by_key(|(range, _)| range.start)
10362                    .collect::<Vec<_>>();
10363                buffer.update(cx, |this, cx| {
10364                    this.edit(edits, None, cx);
10365                })
10366            }
10367            this.refresh_edit_prediction(true, false, window, cx);
10368            refresh_linked_ranges(this, window, cx);
10369        });
10370    }
10371
10372    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10373        if self.read_only(cx) {
10374            return;
10375        }
10376        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10377        self.transact(window, cx, |this, window, cx| {
10378            this.change_selections(Default::default(), window, cx, |s| {
10379                s.move_with(|map, selection| {
10380                    if selection.is_empty() {
10381                        let cursor = movement::right(map, selection.head());
10382                        selection.end = cursor;
10383                        selection.reversed = true;
10384                        selection.goal = SelectionGoal::None;
10385                    }
10386                })
10387            });
10388            this.insert("", window, cx);
10389            this.refresh_edit_prediction(true, false, window, cx);
10390        });
10391    }
10392
10393    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10394        if self.mode.is_single_line() {
10395            cx.propagate();
10396            return;
10397        }
10398
10399        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10400        if self.move_to_prev_snippet_tabstop(window, cx) {
10401            return;
10402        }
10403        self.outdent(&Outdent, window, cx);
10404    }
10405
10406    pub fn next_snippet_tabstop(
10407        &mut self,
10408        _: &NextSnippetTabstop,
10409        window: &mut Window,
10410        cx: &mut Context<Self>,
10411    ) {
10412        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10413            cx.propagate();
10414            return;
10415        }
10416
10417        if self.move_to_next_snippet_tabstop(window, cx) {
10418            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10419            return;
10420        }
10421        cx.propagate();
10422    }
10423
10424    pub fn previous_snippet_tabstop(
10425        &mut self,
10426        _: &PreviousSnippetTabstop,
10427        window: &mut Window,
10428        cx: &mut Context<Self>,
10429    ) {
10430        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10431            cx.propagate();
10432            return;
10433        }
10434
10435        if self.move_to_prev_snippet_tabstop(window, cx) {
10436            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10437            return;
10438        }
10439        cx.propagate();
10440    }
10441
10442    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10443        if self.mode.is_single_line() {
10444            cx.propagate();
10445            return;
10446        }
10447
10448        if self.move_to_next_snippet_tabstop(window, cx) {
10449            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10450            return;
10451        }
10452        if self.read_only(cx) {
10453            return;
10454        }
10455        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10456        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10457        let buffer = self.buffer.read(cx);
10458        let snapshot = buffer.snapshot(cx);
10459        let rows_iter = selections.iter().map(|s| s.head().row);
10460        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10461
10462        let has_some_cursor_in_whitespace = selections
10463            .iter()
10464            .filter(|selection| selection.is_empty())
10465            .any(|selection| {
10466                let cursor = selection.head();
10467                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10468                cursor.column < current_indent.len
10469            });
10470
10471        let mut edits = Vec::new();
10472        let mut prev_edited_row = 0;
10473        let mut row_delta = 0;
10474        for selection in &mut selections {
10475            if selection.start.row != prev_edited_row {
10476                row_delta = 0;
10477            }
10478            prev_edited_row = selection.end.row;
10479
10480            // If the selection is non-empty, then increase the indentation of the selected lines.
10481            if !selection.is_empty() {
10482                row_delta =
10483                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10484                continue;
10485            }
10486
10487            let cursor = selection.head();
10488            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10489            if let Some(suggested_indent) =
10490                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10491            {
10492                // Don't do anything if already at suggested indent
10493                // and there is any other cursor which is not
10494                if has_some_cursor_in_whitespace
10495                    && cursor.column == current_indent.len
10496                    && current_indent.len == suggested_indent.len
10497                {
10498                    continue;
10499                }
10500
10501                // Adjust line and move cursor to suggested indent
10502                // if cursor is not at suggested indent
10503                if cursor.column < suggested_indent.len
10504                    && cursor.column <= current_indent.len
10505                    && current_indent.len <= suggested_indent.len
10506                {
10507                    selection.start = Point::new(cursor.row, suggested_indent.len);
10508                    selection.end = selection.start;
10509                    if row_delta == 0 {
10510                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10511                            cursor.row,
10512                            current_indent,
10513                            suggested_indent,
10514                        ));
10515                        row_delta = suggested_indent.len - current_indent.len;
10516                    }
10517                    continue;
10518                }
10519
10520                // If current indent is more than suggested indent
10521                // only move cursor to current indent and skip indent
10522                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10523                    selection.start = Point::new(cursor.row, current_indent.len);
10524                    selection.end = selection.start;
10525                    continue;
10526                }
10527            }
10528
10529            // Otherwise, insert a hard or soft tab.
10530            let settings = buffer.language_settings_at(cursor, cx);
10531            let tab_size = if settings.hard_tabs {
10532                IndentSize::tab()
10533            } else {
10534                let tab_size = settings.tab_size.get();
10535                let indent_remainder = snapshot
10536                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10537                    .flat_map(str::chars)
10538                    .fold(row_delta % tab_size, |counter: u32, c| {
10539                        if c == '\t' {
10540                            0
10541                        } else {
10542                            (counter + 1) % tab_size
10543                        }
10544                    });
10545
10546                let chars_to_next_tab_stop = tab_size - indent_remainder;
10547                IndentSize::spaces(chars_to_next_tab_stop)
10548            };
10549            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10550            selection.end = selection.start;
10551            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10552            row_delta += tab_size.len;
10553        }
10554
10555        self.transact(window, cx, |this, window, cx| {
10556            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10557            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10558            this.refresh_edit_prediction(true, false, window, cx);
10559        });
10560    }
10561
10562    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10563        if self.read_only(cx) {
10564            return;
10565        }
10566        if self.mode.is_single_line() {
10567            cx.propagate();
10568            return;
10569        }
10570
10571        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10572        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10573        let mut prev_edited_row = 0;
10574        let mut row_delta = 0;
10575        let mut edits = Vec::new();
10576        let buffer = self.buffer.read(cx);
10577        let snapshot = buffer.snapshot(cx);
10578        for selection in &mut selections {
10579            if selection.start.row != prev_edited_row {
10580                row_delta = 0;
10581            }
10582            prev_edited_row = selection.end.row;
10583
10584            row_delta =
10585                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10586        }
10587
10588        self.transact(window, cx, |this, window, cx| {
10589            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10590            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10591        });
10592    }
10593
10594    fn indent_selection(
10595        buffer: &MultiBuffer,
10596        snapshot: &MultiBufferSnapshot,
10597        selection: &mut Selection<Point>,
10598        edits: &mut Vec<(Range<Point>, String)>,
10599        delta_for_start_row: u32,
10600        cx: &App,
10601    ) -> u32 {
10602        let settings = buffer.language_settings_at(selection.start, cx);
10603        let tab_size = settings.tab_size.get();
10604        let indent_kind = if settings.hard_tabs {
10605            IndentKind::Tab
10606        } else {
10607            IndentKind::Space
10608        };
10609        let mut start_row = selection.start.row;
10610        let mut end_row = selection.end.row + 1;
10611
10612        // If a selection ends at the beginning of a line, don't indent
10613        // that last line.
10614        if selection.end.column == 0 && selection.end.row > selection.start.row {
10615            end_row -= 1;
10616        }
10617
10618        // Avoid re-indenting a row that has already been indented by a
10619        // previous selection, but still update this selection's column
10620        // to reflect that indentation.
10621        if delta_for_start_row > 0 {
10622            start_row += 1;
10623            selection.start.column += delta_for_start_row;
10624            if selection.end.row == selection.start.row {
10625                selection.end.column += delta_for_start_row;
10626            }
10627        }
10628
10629        let mut delta_for_end_row = 0;
10630        let has_multiple_rows = start_row + 1 != end_row;
10631        for row in start_row..end_row {
10632            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10633            let indent_delta = match (current_indent.kind, indent_kind) {
10634                (IndentKind::Space, IndentKind::Space) => {
10635                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10636                    IndentSize::spaces(columns_to_next_tab_stop)
10637                }
10638                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10639                (_, IndentKind::Tab) => IndentSize::tab(),
10640            };
10641
10642            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10643                0
10644            } else {
10645                selection.start.column
10646            };
10647            let row_start = Point::new(row, start);
10648            edits.push((
10649                row_start..row_start,
10650                indent_delta.chars().collect::<String>(),
10651            ));
10652
10653            // Update this selection's endpoints to reflect the indentation.
10654            if row == selection.start.row {
10655                selection.start.column += indent_delta.len;
10656            }
10657            if row == selection.end.row {
10658                selection.end.column += indent_delta.len;
10659                delta_for_end_row = indent_delta.len;
10660            }
10661        }
10662
10663        if selection.start.row == selection.end.row {
10664            delta_for_start_row + delta_for_end_row
10665        } else {
10666            delta_for_end_row
10667        }
10668    }
10669
10670    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10671        if self.read_only(cx) {
10672            return;
10673        }
10674        if self.mode.is_single_line() {
10675            cx.propagate();
10676            return;
10677        }
10678
10679        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10680        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10681        let selections = self.selections.all::<Point>(&display_map);
10682        let mut deletion_ranges = Vec::new();
10683        let mut last_outdent = None;
10684        {
10685            let buffer = self.buffer.read(cx);
10686            let snapshot = buffer.snapshot(cx);
10687            for selection in &selections {
10688                let settings = buffer.language_settings_at(selection.start, cx);
10689                let tab_size = settings.tab_size.get();
10690                let mut rows = selection.spanned_rows(false, &display_map);
10691
10692                // Avoid re-outdenting a row that has already been outdented by a
10693                // previous selection.
10694                if let Some(last_row) = last_outdent
10695                    && last_row == rows.start
10696                {
10697                    rows.start = rows.start.next_row();
10698                }
10699                let has_multiple_rows = rows.len() > 1;
10700                for row in rows.iter_rows() {
10701                    let indent_size = snapshot.indent_size_for_line(row);
10702                    if indent_size.len > 0 {
10703                        let deletion_len = match indent_size.kind {
10704                            IndentKind::Space => {
10705                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10706                                if columns_to_prev_tab_stop == 0 {
10707                                    tab_size
10708                                } else {
10709                                    columns_to_prev_tab_stop
10710                                }
10711                            }
10712                            IndentKind::Tab => 1,
10713                        };
10714                        let start = if has_multiple_rows
10715                            || deletion_len > selection.start.column
10716                            || indent_size.len < selection.start.column
10717                        {
10718                            0
10719                        } else {
10720                            selection.start.column - deletion_len
10721                        };
10722                        deletion_ranges.push(
10723                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10724                        );
10725                        last_outdent = Some(row);
10726                    }
10727                }
10728            }
10729        }
10730
10731        self.transact(window, cx, |this, window, cx| {
10732            this.buffer.update(cx, |buffer, cx| {
10733                let empty_str: Arc<str> = Arc::default();
10734                buffer.edit(
10735                    deletion_ranges
10736                        .into_iter()
10737                        .map(|range| (range, empty_str.clone())),
10738                    None,
10739                    cx,
10740                );
10741            });
10742            let selections = this
10743                .selections
10744                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10745            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10746        });
10747    }
10748
10749    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10750        if self.read_only(cx) {
10751            return;
10752        }
10753        if self.mode.is_single_line() {
10754            cx.propagate();
10755            return;
10756        }
10757
10758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10759        let selections = self
10760            .selections
10761            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10762            .into_iter()
10763            .map(|s| s.range());
10764
10765        self.transact(window, cx, |this, window, cx| {
10766            this.buffer.update(cx, |buffer, cx| {
10767                buffer.autoindent_ranges(selections, cx);
10768            });
10769            let selections = this
10770                .selections
10771                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10772            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10773        });
10774    }
10775
10776    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10777        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10778        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10779        let selections = self.selections.all::<Point>(&display_map);
10780
10781        let mut new_cursors = Vec::new();
10782        let mut edit_ranges = Vec::new();
10783        let mut selections = selections.iter().peekable();
10784        while let Some(selection) = selections.next() {
10785            let mut rows = selection.spanned_rows(false, &display_map);
10786
10787            // Accumulate contiguous regions of rows that we want to delete.
10788            while let Some(next_selection) = selections.peek() {
10789                let next_rows = next_selection.spanned_rows(false, &display_map);
10790                if next_rows.start <= rows.end {
10791                    rows.end = next_rows.end;
10792                    selections.next().unwrap();
10793                } else {
10794                    break;
10795                }
10796            }
10797
10798            let buffer = display_map.buffer_snapshot();
10799            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10800            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10801                // If there's a line after the range, delete the \n from the end of the row range
10802                (
10803                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10804                    rows.end,
10805                )
10806            } else {
10807                // If there isn't a line after the range, delete the \n from the line before the
10808                // start of the row range
10809                edit_start = edit_start.saturating_sub_usize(1);
10810                (buffer.len(), rows.start.previous_row())
10811            };
10812
10813            let text_layout_details = self.text_layout_details(window);
10814            let x = display_map.x_for_display_point(
10815                selection.head().to_display_point(&display_map),
10816                &text_layout_details,
10817            );
10818            let row = Point::new(target_row.0, 0)
10819                .to_display_point(&display_map)
10820                .row();
10821            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10822
10823            new_cursors.push((
10824                selection.id,
10825                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10826                SelectionGoal::None,
10827            ));
10828            edit_ranges.push(edit_start..edit_end);
10829        }
10830
10831        self.transact(window, cx, |this, window, cx| {
10832            let buffer = this.buffer.update(cx, |buffer, cx| {
10833                let empty_str: Arc<str> = Arc::default();
10834                buffer.edit(
10835                    edit_ranges
10836                        .into_iter()
10837                        .map(|range| (range, empty_str.clone())),
10838                    None,
10839                    cx,
10840                );
10841                buffer.snapshot(cx)
10842            });
10843            let new_selections = new_cursors
10844                .into_iter()
10845                .map(|(id, cursor, goal)| {
10846                    let cursor = cursor.to_point(&buffer);
10847                    Selection {
10848                        id,
10849                        start: cursor,
10850                        end: cursor,
10851                        reversed: false,
10852                        goal,
10853                    }
10854                })
10855                .collect();
10856
10857            this.change_selections(Default::default(), window, cx, |s| {
10858                s.select(new_selections);
10859            });
10860        });
10861    }
10862
10863    pub fn join_lines_impl(
10864        &mut self,
10865        insert_whitespace: bool,
10866        window: &mut Window,
10867        cx: &mut Context<Self>,
10868    ) {
10869        if self.read_only(cx) {
10870            return;
10871        }
10872        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10873        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10874            let start = MultiBufferRow(selection.start.row);
10875            // Treat single line selections as if they include the next line. Otherwise this action
10876            // would do nothing for single line selections individual cursors.
10877            let end = if selection.start.row == selection.end.row {
10878                MultiBufferRow(selection.start.row + 1)
10879            } else {
10880                MultiBufferRow(selection.end.row)
10881            };
10882
10883            if let Some(last_row_range) = row_ranges.last_mut()
10884                && start <= last_row_range.end
10885            {
10886                last_row_range.end = end;
10887                continue;
10888            }
10889            row_ranges.push(start..end);
10890        }
10891
10892        let snapshot = self.buffer.read(cx).snapshot(cx);
10893        let mut cursor_positions = Vec::new();
10894        for row_range in &row_ranges {
10895            let anchor = snapshot.anchor_before(Point::new(
10896                row_range.end.previous_row().0,
10897                snapshot.line_len(row_range.end.previous_row()),
10898            ));
10899            cursor_positions.push(anchor..anchor);
10900        }
10901
10902        self.transact(window, cx, |this, window, cx| {
10903            for row_range in row_ranges.into_iter().rev() {
10904                for row in row_range.iter_rows().rev() {
10905                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10906                    let next_line_row = row.next_row();
10907                    let indent = snapshot.indent_size_for_line(next_line_row);
10908                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10909
10910                    let replace =
10911                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10912                            " "
10913                        } else {
10914                            ""
10915                        };
10916
10917                    this.buffer.update(cx, |buffer, cx| {
10918                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10919                    });
10920                }
10921            }
10922
10923            this.change_selections(Default::default(), window, cx, |s| {
10924                s.select_anchor_ranges(cursor_positions)
10925            });
10926        });
10927    }
10928
10929    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10930        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10931        self.join_lines_impl(true, window, cx);
10932    }
10933
10934    pub fn sort_lines_case_sensitive(
10935        &mut self,
10936        _: &SortLinesCaseSensitive,
10937        window: &mut Window,
10938        cx: &mut Context<Self>,
10939    ) {
10940        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10941    }
10942
10943    pub fn sort_lines_by_length(
10944        &mut self,
10945        _: &SortLinesByLength,
10946        window: &mut Window,
10947        cx: &mut Context<Self>,
10948    ) {
10949        self.manipulate_immutable_lines(window, cx, |lines| {
10950            lines.sort_by_key(|&line| line.chars().count())
10951        })
10952    }
10953
10954    pub fn sort_lines_case_insensitive(
10955        &mut self,
10956        _: &SortLinesCaseInsensitive,
10957        window: &mut Window,
10958        cx: &mut Context<Self>,
10959    ) {
10960        self.manipulate_immutable_lines(window, cx, |lines| {
10961            lines.sort_by_key(|line| line.to_lowercase())
10962        })
10963    }
10964
10965    pub fn unique_lines_case_insensitive(
10966        &mut self,
10967        _: &UniqueLinesCaseInsensitive,
10968        window: &mut Window,
10969        cx: &mut Context<Self>,
10970    ) {
10971        self.manipulate_immutable_lines(window, cx, |lines| {
10972            let mut seen = HashSet::default();
10973            lines.retain(|line| seen.insert(line.to_lowercase()));
10974        })
10975    }
10976
10977    pub fn unique_lines_case_sensitive(
10978        &mut self,
10979        _: &UniqueLinesCaseSensitive,
10980        window: &mut Window,
10981        cx: &mut Context<Self>,
10982    ) {
10983        self.manipulate_immutable_lines(window, cx, |lines| {
10984            let mut seen = HashSet::default();
10985            lines.retain(|line| seen.insert(*line));
10986        })
10987    }
10988
10989    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10990        let snapshot = self.buffer.read(cx).snapshot(cx);
10991        for selection in self.selections.disjoint_anchors_arc().iter() {
10992            if snapshot
10993                .language_at(selection.start)
10994                .and_then(|lang| lang.config().wrap_characters.as_ref())
10995                .is_some()
10996            {
10997                return true;
10998            }
10999        }
11000        false
11001    }
11002
11003    fn wrap_selections_in_tag(
11004        &mut self,
11005        _: &WrapSelectionsInTag,
11006        window: &mut Window,
11007        cx: &mut Context<Self>,
11008    ) {
11009        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11010
11011        let snapshot = self.buffer.read(cx).snapshot(cx);
11012
11013        let mut edits = Vec::new();
11014        let mut boundaries = Vec::new();
11015
11016        for selection in self
11017            .selections
11018            .all_adjusted(&self.display_snapshot(cx))
11019            .iter()
11020        {
11021            let Some(wrap_config) = snapshot
11022                .language_at(selection.start)
11023                .and_then(|lang| lang.config().wrap_characters.clone())
11024            else {
11025                continue;
11026            };
11027
11028            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11029            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11030
11031            let start_before = snapshot.anchor_before(selection.start);
11032            let end_after = snapshot.anchor_after(selection.end);
11033
11034            edits.push((start_before..start_before, open_tag));
11035            edits.push((end_after..end_after, close_tag));
11036
11037            boundaries.push((
11038                start_before,
11039                end_after,
11040                wrap_config.start_prefix.len(),
11041                wrap_config.end_suffix.len(),
11042            ));
11043        }
11044
11045        if edits.is_empty() {
11046            return;
11047        }
11048
11049        self.transact(window, cx, |this, window, cx| {
11050            let buffer = this.buffer.update(cx, |buffer, cx| {
11051                buffer.edit(edits, None, cx);
11052                buffer.snapshot(cx)
11053            });
11054
11055            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11056            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11057                boundaries.into_iter()
11058            {
11059                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11060                let close_offset = end_after
11061                    .to_offset(&buffer)
11062                    .saturating_sub_usize(end_suffix_len);
11063                new_selections.push(open_offset..open_offset);
11064                new_selections.push(close_offset..close_offset);
11065            }
11066
11067            this.change_selections(Default::default(), window, cx, |s| {
11068                s.select_ranges(new_selections);
11069            });
11070
11071            this.request_autoscroll(Autoscroll::fit(), cx);
11072        });
11073    }
11074
11075    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11076        let Some(project) = self.project.clone() else {
11077            return;
11078        };
11079        self.reload(project, window, cx)
11080            .detach_and_notify_err(window, cx);
11081    }
11082
11083    pub fn restore_file(
11084        &mut self,
11085        _: &::git::RestoreFile,
11086        window: &mut Window,
11087        cx: &mut Context<Self>,
11088    ) {
11089        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11090        let mut buffer_ids = HashSet::default();
11091        let snapshot = self.buffer().read(cx).snapshot(cx);
11092        for selection in self
11093            .selections
11094            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11095        {
11096            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11097        }
11098
11099        let buffer = self.buffer().read(cx);
11100        let ranges = buffer_ids
11101            .into_iter()
11102            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11103            .collect::<Vec<_>>();
11104
11105        self.restore_hunks_in_ranges(ranges, window, cx);
11106    }
11107
11108    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11109        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11110        let selections = self
11111            .selections
11112            .all(&self.display_snapshot(cx))
11113            .into_iter()
11114            .map(|s| s.range())
11115            .collect();
11116        self.restore_hunks_in_ranges(selections, window, cx);
11117    }
11118
11119    pub fn restore_hunks_in_ranges(
11120        &mut self,
11121        ranges: Vec<Range<Point>>,
11122        window: &mut Window,
11123        cx: &mut Context<Editor>,
11124    ) {
11125        let mut revert_changes = HashMap::default();
11126        let chunk_by = self
11127            .snapshot(window, cx)
11128            .hunks_for_ranges(ranges)
11129            .into_iter()
11130            .chunk_by(|hunk| hunk.buffer_id);
11131        for (buffer_id, hunks) in &chunk_by {
11132            let hunks = hunks.collect::<Vec<_>>();
11133            for hunk in &hunks {
11134                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11135            }
11136            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11137        }
11138        drop(chunk_by);
11139        if !revert_changes.is_empty() {
11140            self.transact(window, cx, |editor, window, cx| {
11141                editor.restore(revert_changes, window, cx);
11142            });
11143        }
11144    }
11145
11146    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11147        if let Some(status) = self
11148            .addons
11149            .iter()
11150            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11151        {
11152            return Some(status);
11153        }
11154        self.project
11155            .as_ref()?
11156            .read(cx)
11157            .status_for_buffer_id(buffer_id, cx)
11158    }
11159
11160    pub fn open_active_item_in_terminal(
11161        &mut self,
11162        _: &OpenInTerminal,
11163        window: &mut Window,
11164        cx: &mut Context<Self>,
11165    ) {
11166        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11167            let project_path = buffer.read(cx).project_path(cx)?;
11168            let project = self.project()?.read(cx);
11169            let entry = project.entry_for_path(&project_path, cx)?;
11170            let parent = match &entry.canonical_path {
11171                Some(canonical_path) => canonical_path.to_path_buf(),
11172                None => project.absolute_path(&project_path, cx)?,
11173            }
11174            .parent()?
11175            .to_path_buf();
11176            Some(parent)
11177        }) {
11178            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11179        }
11180    }
11181
11182    fn set_breakpoint_context_menu(
11183        &mut self,
11184        display_row: DisplayRow,
11185        position: Option<Anchor>,
11186        clicked_point: gpui::Point<Pixels>,
11187        window: &mut Window,
11188        cx: &mut Context<Self>,
11189    ) {
11190        let source = self
11191            .buffer
11192            .read(cx)
11193            .snapshot(cx)
11194            .anchor_before(Point::new(display_row.0, 0u32));
11195
11196        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11197
11198        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11199            self,
11200            source,
11201            clicked_point,
11202            context_menu,
11203            window,
11204            cx,
11205        );
11206    }
11207
11208    fn add_edit_breakpoint_block(
11209        &mut self,
11210        anchor: Anchor,
11211        breakpoint: &Breakpoint,
11212        edit_action: BreakpointPromptEditAction,
11213        window: &mut Window,
11214        cx: &mut Context<Self>,
11215    ) {
11216        let weak_editor = cx.weak_entity();
11217        let bp_prompt = cx.new(|cx| {
11218            BreakpointPromptEditor::new(
11219                weak_editor,
11220                anchor,
11221                breakpoint.clone(),
11222                edit_action,
11223                window,
11224                cx,
11225            )
11226        });
11227
11228        let height = bp_prompt.update(cx, |this, cx| {
11229            this.prompt
11230                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11231        });
11232        let cloned_prompt = bp_prompt.clone();
11233        let blocks = vec![BlockProperties {
11234            style: BlockStyle::Sticky,
11235            placement: BlockPlacement::Above(anchor),
11236            height: Some(height),
11237            render: Arc::new(move |cx| {
11238                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11239                cloned_prompt.clone().into_any_element()
11240            }),
11241            priority: 0,
11242        }];
11243
11244        let focus_handle = bp_prompt.focus_handle(cx);
11245        window.focus(&focus_handle);
11246
11247        let block_ids = self.insert_blocks(blocks, None, cx);
11248        bp_prompt.update(cx, |prompt, _| {
11249            prompt.add_block_ids(block_ids);
11250        });
11251    }
11252
11253    pub(crate) fn breakpoint_at_row(
11254        &self,
11255        row: u32,
11256        window: &mut Window,
11257        cx: &mut Context<Self>,
11258    ) -> Option<(Anchor, Breakpoint)> {
11259        let snapshot = self.snapshot(window, cx);
11260        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11261
11262        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11263    }
11264
11265    pub(crate) fn breakpoint_at_anchor(
11266        &self,
11267        breakpoint_position: Anchor,
11268        snapshot: &EditorSnapshot,
11269        cx: &mut Context<Self>,
11270    ) -> Option<(Anchor, Breakpoint)> {
11271        let buffer = self
11272            .buffer
11273            .read(cx)
11274            .buffer_for_anchor(breakpoint_position, cx)?;
11275
11276        let enclosing_excerpt = breakpoint_position.excerpt_id;
11277        let buffer_snapshot = buffer.read(cx).snapshot();
11278
11279        let row = buffer_snapshot
11280            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11281            .row;
11282
11283        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11284        let anchor_end = snapshot
11285            .buffer_snapshot()
11286            .anchor_after(Point::new(row, line_len));
11287
11288        self.breakpoint_store
11289            .as_ref()?
11290            .read_with(cx, |breakpoint_store, cx| {
11291                breakpoint_store
11292                    .breakpoints(
11293                        &buffer,
11294                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11295                        &buffer_snapshot,
11296                        cx,
11297                    )
11298                    .next()
11299                    .and_then(|(bp, _)| {
11300                        let breakpoint_row = buffer_snapshot
11301                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11302                            .row;
11303
11304                        if breakpoint_row == row {
11305                            snapshot
11306                                .buffer_snapshot()
11307                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11308                                .map(|position| (position, bp.bp.clone()))
11309                        } else {
11310                            None
11311                        }
11312                    })
11313            })
11314    }
11315
11316    pub fn edit_log_breakpoint(
11317        &mut self,
11318        _: &EditLogBreakpoint,
11319        window: &mut Window,
11320        cx: &mut Context<Self>,
11321    ) {
11322        if self.breakpoint_store.is_none() {
11323            return;
11324        }
11325
11326        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11327            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11328                message: None,
11329                state: BreakpointState::Enabled,
11330                condition: None,
11331                hit_condition: None,
11332            });
11333
11334            self.add_edit_breakpoint_block(
11335                anchor,
11336                &breakpoint,
11337                BreakpointPromptEditAction::Log,
11338                window,
11339                cx,
11340            );
11341        }
11342    }
11343
11344    fn breakpoints_at_cursors(
11345        &self,
11346        window: &mut Window,
11347        cx: &mut Context<Self>,
11348    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11349        let snapshot = self.snapshot(window, cx);
11350        let cursors = self
11351            .selections
11352            .disjoint_anchors_arc()
11353            .iter()
11354            .map(|selection| {
11355                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11356
11357                let breakpoint_position = self
11358                    .breakpoint_at_row(cursor_position.row, window, cx)
11359                    .map(|bp| bp.0)
11360                    .unwrap_or_else(|| {
11361                        snapshot
11362                            .display_snapshot
11363                            .buffer_snapshot()
11364                            .anchor_after(Point::new(cursor_position.row, 0))
11365                    });
11366
11367                let breakpoint = self
11368                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11369                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11370
11371                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11372            })
11373            // 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.
11374            .collect::<HashMap<Anchor, _>>();
11375
11376        cursors.into_iter().collect()
11377    }
11378
11379    pub fn enable_breakpoint(
11380        &mut self,
11381        _: &crate::actions::EnableBreakpoint,
11382        window: &mut Window,
11383        cx: &mut Context<Self>,
11384    ) {
11385        if self.breakpoint_store.is_none() {
11386            return;
11387        }
11388
11389        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11390            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11391                continue;
11392            };
11393            self.edit_breakpoint_at_anchor(
11394                anchor,
11395                breakpoint,
11396                BreakpointEditAction::InvertState,
11397                cx,
11398            );
11399        }
11400    }
11401
11402    pub fn disable_breakpoint(
11403        &mut self,
11404        _: &crate::actions::DisableBreakpoint,
11405        window: &mut Window,
11406        cx: &mut Context<Self>,
11407    ) {
11408        if self.breakpoint_store.is_none() {
11409            return;
11410        }
11411
11412        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11413            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11414                continue;
11415            };
11416            self.edit_breakpoint_at_anchor(
11417                anchor,
11418                breakpoint,
11419                BreakpointEditAction::InvertState,
11420                cx,
11421            );
11422        }
11423    }
11424
11425    pub fn toggle_breakpoint(
11426        &mut self,
11427        _: &crate::actions::ToggleBreakpoint,
11428        window: &mut Window,
11429        cx: &mut Context<Self>,
11430    ) {
11431        if self.breakpoint_store.is_none() {
11432            return;
11433        }
11434
11435        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11436            if let Some(breakpoint) = breakpoint {
11437                self.edit_breakpoint_at_anchor(
11438                    anchor,
11439                    breakpoint,
11440                    BreakpointEditAction::Toggle,
11441                    cx,
11442                );
11443            } else {
11444                self.edit_breakpoint_at_anchor(
11445                    anchor,
11446                    Breakpoint::new_standard(),
11447                    BreakpointEditAction::Toggle,
11448                    cx,
11449                );
11450            }
11451        }
11452    }
11453
11454    pub fn edit_breakpoint_at_anchor(
11455        &mut self,
11456        breakpoint_position: Anchor,
11457        breakpoint: Breakpoint,
11458        edit_action: BreakpointEditAction,
11459        cx: &mut Context<Self>,
11460    ) {
11461        let Some(breakpoint_store) = &self.breakpoint_store else {
11462            return;
11463        };
11464
11465        let Some(buffer) = self
11466            .buffer
11467            .read(cx)
11468            .buffer_for_anchor(breakpoint_position, cx)
11469        else {
11470            return;
11471        };
11472
11473        breakpoint_store.update(cx, |breakpoint_store, cx| {
11474            breakpoint_store.toggle_breakpoint(
11475                buffer,
11476                BreakpointWithPosition {
11477                    position: breakpoint_position.text_anchor,
11478                    bp: breakpoint,
11479                },
11480                edit_action,
11481                cx,
11482            );
11483        });
11484
11485        cx.notify();
11486    }
11487
11488    #[cfg(any(test, feature = "test-support"))]
11489    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11490        self.breakpoint_store.clone()
11491    }
11492
11493    pub fn prepare_restore_change(
11494        &self,
11495        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11496        hunk: &MultiBufferDiffHunk,
11497        cx: &mut App,
11498    ) -> Option<()> {
11499        if hunk.is_created_file() {
11500            return None;
11501        }
11502        let buffer = self.buffer.read(cx);
11503        let diff = buffer.diff_for(hunk.buffer_id)?;
11504        let buffer = buffer.buffer(hunk.buffer_id)?;
11505        let buffer = buffer.read(cx);
11506        let original_text = diff
11507            .read(cx)
11508            .base_text()
11509            .as_rope()
11510            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11511        let buffer_snapshot = buffer.snapshot();
11512        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11513        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11514            probe
11515                .0
11516                .start
11517                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11518                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11519        }) {
11520            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11521            Some(())
11522        } else {
11523            None
11524        }
11525    }
11526
11527    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11528        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11529    }
11530
11531    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11532        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11533    }
11534
11535    pub fn rotate_selections_forward(
11536        &mut self,
11537        _: &RotateSelectionsForward,
11538        window: &mut Window,
11539        cx: &mut Context<Self>,
11540    ) {
11541        self.rotate_selections(window, cx, false)
11542    }
11543
11544    pub fn rotate_selections_backward(
11545        &mut self,
11546        _: &RotateSelectionsBackward,
11547        window: &mut Window,
11548        cx: &mut Context<Self>,
11549    ) {
11550        self.rotate_selections(window, cx, true)
11551    }
11552
11553    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11554        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11555        let display_snapshot = self.display_snapshot(cx);
11556        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11557
11558        if selections.len() < 2 {
11559            return;
11560        }
11561
11562        let (edits, new_selections) = {
11563            let buffer = self.buffer.read(cx).read(cx);
11564            let has_selections = selections.iter().any(|s| !s.is_empty());
11565            if has_selections {
11566                let mut selected_texts: Vec<String> = selections
11567                    .iter()
11568                    .map(|selection| {
11569                        buffer
11570                            .text_for_range(selection.start..selection.end)
11571                            .collect()
11572                    })
11573                    .collect();
11574
11575                if reverse {
11576                    selected_texts.rotate_left(1);
11577                } else {
11578                    selected_texts.rotate_right(1);
11579                }
11580
11581                let mut offset_delta: i64 = 0;
11582                let mut new_selections = Vec::new();
11583                let edits: Vec<_> = selections
11584                    .iter()
11585                    .zip(selected_texts.iter())
11586                    .map(|(selection, new_text)| {
11587                        let old_len = (selection.end.0 - selection.start.0) as i64;
11588                        let new_len = new_text.len() as i64;
11589                        let adjusted_start =
11590                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11591                        let adjusted_end =
11592                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11593
11594                        new_selections.push(Selection {
11595                            id: selection.id,
11596                            start: adjusted_start,
11597                            end: adjusted_end,
11598                            reversed: selection.reversed,
11599                            goal: selection.goal,
11600                        });
11601
11602                        offset_delta += new_len - old_len;
11603                        (selection.start..selection.end, new_text.clone())
11604                    })
11605                    .collect();
11606                (edits, new_selections)
11607            } else {
11608                let mut all_rows: Vec<u32> = selections
11609                    .iter()
11610                    .map(|selection| buffer.offset_to_point(selection.start).row)
11611                    .collect();
11612                all_rows.sort_unstable();
11613                all_rows.dedup();
11614
11615                if all_rows.len() < 2 {
11616                    return;
11617                }
11618
11619                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11620                    .iter()
11621                    .map(|&row| {
11622                        let start = Point::new(row, 0);
11623                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11624                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11625                    })
11626                    .collect();
11627
11628                let mut line_texts: Vec<String> = line_ranges
11629                    .iter()
11630                    .map(|range| buffer.text_for_range(range.clone()).collect())
11631                    .collect();
11632
11633                if reverse {
11634                    line_texts.rotate_left(1);
11635                } else {
11636                    line_texts.rotate_right(1);
11637                }
11638
11639                let edits = line_ranges
11640                    .iter()
11641                    .zip(line_texts.iter())
11642                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11643                    .collect();
11644
11645                let num_rows = all_rows.len();
11646                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11647                    .iter()
11648                    .enumerate()
11649                    .map(|(i, &row)| (row, i))
11650                    .collect();
11651
11652                // Compute new line start offsets after rotation (handles CRLF)
11653                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11654                let first_line_start = line_ranges[0].start.0;
11655                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11656                for text in line_texts.iter().take(num_rows - 1) {
11657                    let prev_start = *new_line_starts.last().unwrap();
11658                    new_line_starts.push(prev_start + text.len() + newline_len);
11659                }
11660
11661                let new_selections = selections
11662                    .iter()
11663                    .map(|selection| {
11664                        let point = buffer.offset_to_point(selection.start);
11665                        let old_index = row_to_index[&point.row];
11666                        let new_index = if reverse {
11667                            (old_index + num_rows - 1) % num_rows
11668                        } else {
11669                            (old_index + 1) % num_rows
11670                        };
11671                        let new_offset =
11672                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11673                        Selection {
11674                            id: selection.id,
11675                            start: new_offset,
11676                            end: new_offset,
11677                            reversed: selection.reversed,
11678                            goal: selection.goal,
11679                        }
11680                    })
11681                    .collect();
11682
11683                (edits, new_selections)
11684            }
11685        };
11686
11687        self.transact(window, cx, |this, window, cx| {
11688            this.buffer.update(cx, |buffer, cx| {
11689                buffer.edit(edits, None, cx);
11690            });
11691            this.change_selections(Default::default(), window, cx, |s| {
11692                s.select(new_selections);
11693            });
11694        });
11695    }
11696
11697    fn manipulate_lines<M>(
11698        &mut self,
11699        window: &mut Window,
11700        cx: &mut Context<Self>,
11701        mut manipulate: M,
11702    ) where
11703        M: FnMut(&str) -> LineManipulationResult,
11704    {
11705        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11706
11707        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11708        let buffer = self.buffer.read(cx).snapshot(cx);
11709
11710        let mut edits = Vec::new();
11711
11712        let selections = self.selections.all::<Point>(&display_map);
11713        let mut selections = selections.iter().peekable();
11714        let mut contiguous_row_selections = Vec::new();
11715        let mut new_selections = Vec::new();
11716        let mut added_lines = 0;
11717        let mut removed_lines = 0;
11718
11719        while let Some(selection) = selections.next() {
11720            let (start_row, end_row) = consume_contiguous_rows(
11721                &mut contiguous_row_selections,
11722                selection,
11723                &display_map,
11724                &mut selections,
11725            );
11726
11727            let start_point = Point::new(start_row.0, 0);
11728            let end_point = Point::new(
11729                end_row.previous_row().0,
11730                buffer.line_len(end_row.previous_row()),
11731            );
11732            let text = buffer
11733                .text_for_range(start_point..end_point)
11734                .collect::<String>();
11735
11736            let LineManipulationResult {
11737                new_text,
11738                line_count_before,
11739                line_count_after,
11740            } = manipulate(&text);
11741
11742            edits.push((start_point..end_point, new_text));
11743
11744            // Selections must change based on added and removed line count
11745            let start_row =
11746                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11747            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11748            new_selections.push(Selection {
11749                id: selection.id,
11750                start: start_row,
11751                end: end_row,
11752                goal: SelectionGoal::None,
11753                reversed: selection.reversed,
11754            });
11755
11756            if line_count_after > line_count_before {
11757                added_lines += line_count_after - line_count_before;
11758            } else if line_count_before > line_count_after {
11759                removed_lines += line_count_before - line_count_after;
11760            }
11761        }
11762
11763        self.transact(window, cx, |this, window, cx| {
11764            let buffer = this.buffer.update(cx, |buffer, cx| {
11765                buffer.edit(edits, None, cx);
11766                buffer.snapshot(cx)
11767            });
11768
11769            // Recalculate offsets on newly edited buffer
11770            let new_selections = new_selections
11771                .iter()
11772                .map(|s| {
11773                    let start_point = Point::new(s.start.0, 0);
11774                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11775                    Selection {
11776                        id: s.id,
11777                        start: buffer.point_to_offset(start_point),
11778                        end: buffer.point_to_offset(end_point),
11779                        goal: s.goal,
11780                        reversed: s.reversed,
11781                    }
11782                })
11783                .collect();
11784
11785            this.change_selections(Default::default(), window, cx, |s| {
11786                s.select(new_selections);
11787            });
11788
11789            this.request_autoscroll(Autoscroll::fit(), cx);
11790        });
11791    }
11792
11793    fn manipulate_immutable_lines<Fn>(
11794        &mut self,
11795        window: &mut Window,
11796        cx: &mut Context<Self>,
11797        mut callback: Fn,
11798    ) where
11799        Fn: FnMut(&mut Vec<&str>),
11800    {
11801        self.manipulate_lines(window, cx, |text| {
11802            let mut lines: Vec<&str> = text.split('\n').collect();
11803            let line_count_before = lines.len();
11804
11805            callback(&mut lines);
11806
11807            LineManipulationResult {
11808                new_text: lines.join("\n"),
11809                line_count_before,
11810                line_count_after: lines.len(),
11811            }
11812        });
11813    }
11814
11815    fn manipulate_mutable_lines<Fn>(
11816        &mut self,
11817        window: &mut Window,
11818        cx: &mut Context<Self>,
11819        mut callback: Fn,
11820    ) where
11821        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11822    {
11823        self.manipulate_lines(window, cx, |text| {
11824            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11825            let line_count_before = lines.len();
11826
11827            callback(&mut lines);
11828
11829            LineManipulationResult {
11830                new_text: lines.join("\n"),
11831                line_count_before,
11832                line_count_after: lines.len(),
11833            }
11834        });
11835    }
11836
11837    pub fn convert_indentation_to_spaces(
11838        &mut self,
11839        _: &ConvertIndentationToSpaces,
11840        window: &mut Window,
11841        cx: &mut Context<Self>,
11842    ) {
11843        let settings = self.buffer.read(cx).language_settings(cx);
11844        let tab_size = settings.tab_size.get() as usize;
11845
11846        self.manipulate_mutable_lines(window, cx, |lines| {
11847            // Allocates a reasonably sized scratch buffer once for the whole loop
11848            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11849            // Avoids recomputing spaces that could be inserted many times
11850            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11851                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11852                .collect();
11853
11854            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11855                let mut chars = line.as_ref().chars();
11856                let mut col = 0;
11857                let mut changed = false;
11858
11859                for ch in chars.by_ref() {
11860                    match ch {
11861                        ' ' => {
11862                            reindented_line.push(' ');
11863                            col += 1;
11864                        }
11865                        '\t' => {
11866                            // \t are converted to spaces depending on the current column
11867                            let spaces_len = tab_size - (col % tab_size);
11868                            reindented_line.extend(&space_cache[spaces_len - 1]);
11869                            col += spaces_len;
11870                            changed = true;
11871                        }
11872                        _ => {
11873                            // If we dont append before break, the character is consumed
11874                            reindented_line.push(ch);
11875                            break;
11876                        }
11877                    }
11878                }
11879
11880                if !changed {
11881                    reindented_line.clear();
11882                    continue;
11883                }
11884                // Append the rest of the line and replace old reference with new one
11885                reindented_line.extend(chars);
11886                *line = Cow::Owned(reindented_line.clone());
11887                reindented_line.clear();
11888            }
11889        });
11890    }
11891
11892    pub fn convert_indentation_to_tabs(
11893        &mut self,
11894        _: &ConvertIndentationToTabs,
11895        window: &mut Window,
11896        cx: &mut Context<Self>,
11897    ) {
11898        let settings = self.buffer.read(cx).language_settings(cx);
11899        let tab_size = settings.tab_size.get() as usize;
11900
11901        self.manipulate_mutable_lines(window, cx, |lines| {
11902            // Allocates a reasonably sized buffer once for the whole loop
11903            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11904            // Avoids recomputing spaces that could be inserted many times
11905            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11906                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11907                .collect();
11908
11909            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11910                let mut chars = line.chars();
11911                let mut spaces_count = 0;
11912                let mut first_non_indent_char = None;
11913                let mut changed = false;
11914
11915                for ch in chars.by_ref() {
11916                    match ch {
11917                        ' ' => {
11918                            // Keep track of spaces. Append \t when we reach tab_size
11919                            spaces_count += 1;
11920                            changed = true;
11921                            if spaces_count == tab_size {
11922                                reindented_line.push('\t');
11923                                spaces_count = 0;
11924                            }
11925                        }
11926                        '\t' => {
11927                            reindented_line.push('\t');
11928                            spaces_count = 0;
11929                        }
11930                        _ => {
11931                            // Dont append it yet, we might have remaining spaces
11932                            first_non_indent_char = Some(ch);
11933                            break;
11934                        }
11935                    }
11936                }
11937
11938                if !changed {
11939                    reindented_line.clear();
11940                    continue;
11941                }
11942                // Remaining spaces that didn't make a full tab stop
11943                if spaces_count > 0 {
11944                    reindented_line.extend(&space_cache[spaces_count - 1]);
11945                }
11946                // If we consume an extra character that was not indentation, add it back
11947                if let Some(extra_char) = first_non_indent_char {
11948                    reindented_line.push(extra_char);
11949                }
11950                // Append the rest of the line and replace old reference with new one
11951                reindented_line.extend(chars);
11952                *line = Cow::Owned(reindented_line.clone());
11953                reindented_line.clear();
11954            }
11955        });
11956    }
11957
11958    pub fn convert_to_upper_case(
11959        &mut self,
11960        _: &ConvertToUpperCase,
11961        window: &mut Window,
11962        cx: &mut Context<Self>,
11963    ) {
11964        self.manipulate_text(window, cx, |text| text.to_uppercase())
11965    }
11966
11967    pub fn convert_to_lower_case(
11968        &mut self,
11969        _: &ConvertToLowerCase,
11970        window: &mut Window,
11971        cx: &mut Context<Self>,
11972    ) {
11973        self.manipulate_text(window, cx, |text| text.to_lowercase())
11974    }
11975
11976    pub fn convert_to_title_case(
11977        &mut self,
11978        _: &ConvertToTitleCase,
11979        window: &mut Window,
11980        cx: &mut Context<Self>,
11981    ) {
11982        self.manipulate_text(window, cx, |text| {
11983            text.split('\n')
11984                .map(|line| line.to_case(Case::Title))
11985                .join("\n")
11986        })
11987    }
11988
11989    pub fn convert_to_snake_case(
11990        &mut self,
11991        _: &ConvertToSnakeCase,
11992        window: &mut Window,
11993        cx: &mut Context<Self>,
11994    ) {
11995        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11996    }
11997
11998    pub fn convert_to_kebab_case(
11999        &mut self,
12000        _: &ConvertToKebabCase,
12001        window: &mut Window,
12002        cx: &mut Context<Self>,
12003    ) {
12004        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12005    }
12006
12007    pub fn convert_to_upper_camel_case(
12008        &mut self,
12009        _: &ConvertToUpperCamelCase,
12010        window: &mut Window,
12011        cx: &mut Context<Self>,
12012    ) {
12013        self.manipulate_text(window, cx, |text| {
12014            text.split('\n')
12015                .map(|line| line.to_case(Case::UpperCamel))
12016                .join("\n")
12017        })
12018    }
12019
12020    pub fn convert_to_lower_camel_case(
12021        &mut self,
12022        _: &ConvertToLowerCamelCase,
12023        window: &mut Window,
12024        cx: &mut Context<Self>,
12025    ) {
12026        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12027    }
12028
12029    pub fn convert_to_opposite_case(
12030        &mut self,
12031        _: &ConvertToOppositeCase,
12032        window: &mut Window,
12033        cx: &mut Context<Self>,
12034    ) {
12035        self.manipulate_text(window, cx, |text| {
12036            text.chars()
12037                .fold(String::with_capacity(text.len()), |mut t, c| {
12038                    if c.is_uppercase() {
12039                        t.extend(c.to_lowercase());
12040                    } else {
12041                        t.extend(c.to_uppercase());
12042                    }
12043                    t
12044                })
12045        })
12046    }
12047
12048    pub fn convert_to_sentence_case(
12049        &mut self,
12050        _: &ConvertToSentenceCase,
12051        window: &mut Window,
12052        cx: &mut Context<Self>,
12053    ) {
12054        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12055    }
12056
12057    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12058        self.manipulate_text(window, cx, |text| {
12059            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12060            if has_upper_case_characters {
12061                text.to_lowercase()
12062            } else {
12063                text.to_uppercase()
12064            }
12065        })
12066    }
12067
12068    pub fn convert_to_rot13(
12069        &mut self,
12070        _: &ConvertToRot13,
12071        window: &mut Window,
12072        cx: &mut Context<Self>,
12073    ) {
12074        self.manipulate_text(window, cx, |text| {
12075            text.chars()
12076                .map(|c| match c {
12077                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12078                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12079                    _ => c,
12080                })
12081                .collect()
12082        })
12083    }
12084
12085    pub fn convert_to_rot47(
12086        &mut self,
12087        _: &ConvertToRot47,
12088        window: &mut Window,
12089        cx: &mut Context<Self>,
12090    ) {
12091        self.manipulate_text(window, cx, |text| {
12092            text.chars()
12093                .map(|c| {
12094                    let code_point = c as u32;
12095                    if code_point >= 33 && code_point <= 126 {
12096                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12097                    }
12098                    c
12099                })
12100                .collect()
12101        })
12102    }
12103
12104    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12105    where
12106        Fn: FnMut(&str) -> String,
12107    {
12108        let buffer = self.buffer.read(cx).snapshot(cx);
12109
12110        let mut new_selections = Vec::new();
12111        let mut edits = Vec::new();
12112        let mut selection_adjustment = 0isize;
12113
12114        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12115            let selection_is_empty = selection.is_empty();
12116
12117            let (start, end) = if selection_is_empty {
12118                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12119                (word_range.start, word_range.end)
12120            } else {
12121                (
12122                    buffer.point_to_offset(selection.start),
12123                    buffer.point_to_offset(selection.end),
12124                )
12125            };
12126
12127            let text = buffer.text_for_range(start..end).collect::<String>();
12128            let old_length = text.len() as isize;
12129            let text = callback(&text);
12130
12131            new_selections.push(Selection {
12132                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12133                end: MultiBufferOffset(
12134                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12135                ),
12136                goal: SelectionGoal::None,
12137                id: selection.id,
12138                reversed: selection.reversed,
12139            });
12140
12141            selection_adjustment += old_length - text.len() as isize;
12142
12143            edits.push((start..end, text));
12144        }
12145
12146        self.transact(window, cx, |this, window, cx| {
12147            this.buffer.update(cx, |buffer, cx| {
12148                buffer.edit(edits, None, cx);
12149            });
12150
12151            this.change_selections(Default::default(), window, cx, |s| {
12152                s.select(new_selections);
12153            });
12154
12155            this.request_autoscroll(Autoscroll::fit(), cx);
12156        });
12157    }
12158
12159    pub fn move_selection_on_drop(
12160        &mut self,
12161        selection: &Selection<Anchor>,
12162        target: DisplayPoint,
12163        is_cut: bool,
12164        window: &mut Window,
12165        cx: &mut Context<Self>,
12166    ) {
12167        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12168        let buffer = display_map.buffer_snapshot();
12169        let mut edits = Vec::new();
12170        let insert_point = display_map
12171            .clip_point(target, Bias::Left)
12172            .to_point(&display_map);
12173        let text = buffer
12174            .text_for_range(selection.start..selection.end)
12175            .collect::<String>();
12176        if is_cut {
12177            edits.push(((selection.start..selection.end), String::new()));
12178        }
12179        let insert_anchor = buffer.anchor_before(insert_point);
12180        edits.push(((insert_anchor..insert_anchor), text));
12181        let last_edit_start = insert_anchor.bias_left(buffer);
12182        let last_edit_end = insert_anchor.bias_right(buffer);
12183        self.transact(window, cx, |this, window, cx| {
12184            this.buffer.update(cx, |buffer, cx| {
12185                buffer.edit(edits, None, cx);
12186            });
12187            this.change_selections(Default::default(), window, cx, |s| {
12188                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12189            });
12190        });
12191    }
12192
12193    pub fn clear_selection_drag_state(&mut self) {
12194        self.selection_drag_state = SelectionDragState::None;
12195    }
12196
12197    pub fn duplicate(
12198        &mut self,
12199        upwards: bool,
12200        whole_lines: bool,
12201        window: &mut Window,
12202        cx: &mut Context<Self>,
12203    ) {
12204        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12205
12206        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12207        let buffer = display_map.buffer_snapshot();
12208        let selections = self.selections.all::<Point>(&display_map);
12209
12210        let mut edits = Vec::new();
12211        let mut selections_iter = selections.iter().peekable();
12212        while let Some(selection) = selections_iter.next() {
12213            let mut rows = selection.spanned_rows(false, &display_map);
12214            // duplicate line-wise
12215            if whole_lines || selection.start == selection.end {
12216                // Avoid duplicating the same lines twice.
12217                while let Some(next_selection) = selections_iter.peek() {
12218                    let next_rows = next_selection.spanned_rows(false, &display_map);
12219                    if next_rows.start < rows.end {
12220                        rows.end = next_rows.end;
12221                        selections_iter.next().unwrap();
12222                    } else {
12223                        break;
12224                    }
12225                }
12226
12227                // Copy the text from the selected row region and splice it either at the start
12228                // or end of the region.
12229                let start = Point::new(rows.start.0, 0);
12230                let end = Point::new(
12231                    rows.end.previous_row().0,
12232                    buffer.line_len(rows.end.previous_row()),
12233                );
12234
12235                let mut text = buffer.text_for_range(start..end).collect::<String>();
12236
12237                let insert_location = if upwards {
12238                    // When duplicating upward, we need to insert before the current line.
12239                    // If we're on the last line and it doesn't end with a newline,
12240                    // we need to add a newline before the duplicated content.
12241                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12242                        && buffer.max_point().column > 0
12243                        && !text.ends_with('\n');
12244
12245                    if needs_leading_newline {
12246                        text.insert(0, '\n');
12247                        end
12248                    } else {
12249                        text.push('\n');
12250                        Point::new(rows.start.0, 0)
12251                    }
12252                } else {
12253                    text.push('\n');
12254                    start
12255                };
12256                edits.push((insert_location..insert_location, text));
12257            } else {
12258                // duplicate character-wise
12259                let start = selection.start;
12260                let end = selection.end;
12261                let text = buffer.text_for_range(start..end).collect::<String>();
12262                edits.push((selection.end..selection.end, text));
12263            }
12264        }
12265
12266        self.transact(window, cx, |this, window, cx| {
12267            this.buffer.update(cx, |buffer, cx| {
12268                buffer.edit(edits, None, cx);
12269            });
12270
12271            // When duplicating upward with whole lines, move the cursor to the duplicated line
12272            if upwards && whole_lines {
12273                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12274
12275                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12276                    let mut new_ranges = Vec::new();
12277                    let selections = s.all::<Point>(&display_map);
12278                    let mut selections_iter = selections.iter().peekable();
12279
12280                    while let Some(first_selection) = selections_iter.next() {
12281                        // Group contiguous selections together to find the total row span
12282                        let mut group_selections = vec![first_selection];
12283                        let mut rows = first_selection.spanned_rows(false, &display_map);
12284
12285                        while let Some(next_selection) = selections_iter.peek() {
12286                            let next_rows = next_selection.spanned_rows(false, &display_map);
12287                            if next_rows.start < rows.end {
12288                                rows.end = next_rows.end;
12289                                group_selections.push(selections_iter.next().unwrap());
12290                            } else {
12291                                break;
12292                            }
12293                        }
12294
12295                        let row_count = rows.end.0 - rows.start.0;
12296
12297                        // Move all selections in this group up by the total number of duplicated rows
12298                        for selection in group_selections {
12299                            let new_start = Point::new(
12300                                selection.start.row.saturating_sub(row_count),
12301                                selection.start.column,
12302                            );
12303
12304                            let new_end = Point::new(
12305                                selection.end.row.saturating_sub(row_count),
12306                                selection.end.column,
12307                            );
12308
12309                            new_ranges.push(new_start..new_end);
12310                        }
12311                    }
12312
12313                    s.select_ranges(new_ranges);
12314                });
12315            }
12316
12317            this.request_autoscroll(Autoscroll::fit(), cx);
12318        });
12319    }
12320
12321    pub fn duplicate_line_up(
12322        &mut self,
12323        _: &DuplicateLineUp,
12324        window: &mut Window,
12325        cx: &mut Context<Self>,
12326    ) {
12327        self.duplicate(true, true, window, cx);
12328    }
12329
12330    pub fn duplicate_line_down(
12331        &mut self,
12332        _: &DuplicateLineDown,
12333        window: &mut Window,
12334        cx: &mut Context<Self>,
12335    ) {
12336        self.duplicate(false, true, window, cx);
12337    }
12338
12339    pub fn duplicate_selection(
12340        &mut self,
12341        _: &DuplicateSelection,
12342        window: &mut Window,
12343        cx: &mut Context<Self>,
12344    ) {
12345        self.duplicate(false, false, window, cx);
12346    }
12347
12348    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12349        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12350        if self.mode.is_single_line() {
12351            cx.propagate();
12352            return;
12353        }
12354
12355        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12356        let buffer = self.buffer.read(cx).snapshot(cx);
12357
12358        let mut edits = Vec::new();
12359        let mut unfold_ranges = Vec::new();
12360        let mut refold_creases = Vec::new();
12361
12362        let selections = self.selections.all::<Point>(&display_map);
12363        let mut selections = selections.iter().peekable();
12364        let mut contiguous_row_selections = Vec::new();
12365        let mut new_selections = Vec::new();
12366
12367        while let Some(selection) = selections.next() {
12368            // Find all the selections that span a contiguous row range
12369            let (start_row, end_row) = consume_contiguous_rows(
12370                &mut contiguous_row_selections,
12371                selection,
12372                &display_map,
12373                &mut selections,
12374            );
12375
12376            // Move the text spanned by the row range to be before the line preceding the row range
12377            if start_row.0 > 0 {
12378                let range_to_move = Point::new(
12379                    start_row.previous_row().0,
12380                    buffer.line_len(start_row.previous_row()),
12381                )
12382                    ..Point::new(
12383                        end_row.previous_row().0,
12384                        buffer.line_len(end_row.previous_row()),
12385                    );
12386                let insertion_point = display_map
12387                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12388                    .0;
12389
12390                // Don't move lines across excerpts
12391                if buffer
12392                    .excerpt_containing(insertion_point..range_to_move.end)
12393                    .is_some()
12394                {
12395                    let text = buffer
12396                        .text_for_range(range_to_move.clone())
12397                        .flat_map(|s| s.chars())
12398                        .skip(1)
12399                        .chain(['\n'])
12400                        .collect::<String>();
12401
12402                    edits.push((
12403                        buffer.anchor_after(range_to_move.start)
12404                            ..buffer.anchor_before(range_to_move.end),
12405                        String::new(),
12406                    ));
12407                    let insertion_anchor = buffer.anchor_after(insertion_point);
12408                    edits.push((insertion_anchor..insertion_anchor, text));
12409
12410                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12411
12412                    // Move selections up
12413                    new_selections.extend(contiguous_row_selections.drain(..).map(
12414                        |mut selection| {
12415                            selection.start.row -= row_delta;
12416                            selection.end.row -= row_delta;
12417                            selection
12418                        },
12419                    ));
12420
12421                    // Move folds up
12422                    unfold_ranges.push(range_to_move.clone());
12423                    for fold in display_map.folds_in_range(
12424                        buffer.anchor_before(range_to_move.start)
12425                            ..buffer.anchor_after(range_to_move.end),
12426                    ) {
12427                        let mut start = fold.range.start.to_point(&buffer);
12428                        let mut end = fold.range.end.to_point(&buffer);
12429                        start.row -= row_delta;
12430                        end.row -= row_delta;
12431                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12432                    }
12433                }
12434            }
12435
12436            // If we didn't move line(s), preserve the existing selections
12437            new_selections.append(&mut contiguous_row_selections);
12438        }
12439
12440        self.transact(window, cx, |this, window, cx| {
12441            this.unfold_ranges(&unfold_ranges, true, true, cx);
12442            this.buffer.update(cx, |buffer, cx| {
12443                for (range, text) in edits {
12444                    buffer.edit([(range, text)], None, cx);
12445                }
12446            });
12447            this.fold_creases(refold_creases, true, window, cx);
12448            this.change_selections(Default::default(), window, cx, |s| {
12449                s.select(new_selections);
12450            })
12451        });
12452    }
12453
12454    pub fn move_line_down(
12455        &mut self,
12456        _: &MoveLineDown,
12457        window: &mut Window,
12458        cx: &mut Context<Self>,
12459    ) {
12460        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12461        if self.mode.is_single_line() {
12462            cx.propagate();
12463            return;
12464        }
12465
12466        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12467        let buffer = self.buffer.read(cx).snapshot(cx);
12468
12469        let mut edits = Vec::new();
12470        let mut unfold_ranges = Vec::new();
12471        let mut refold_creases = Vec::new();
12472
12473        let selections = self.selections.all::<Point>(&display_map);
12474        let mut selections = selections.iter().peekable();
12475        let mut contiguous_row_selections = Vec::new();
12476        let mut new_selections = Vec::new();
12477
12478        while let Some(selection) = selections.next() {
12479            // Find all the selections that span a contiguous row range
12480            let (start_row, end_row) = consume_contiguous_rows(
12481                &mut contiguous_row_selections,
12482                selection,
12483                &display_map,
12484                &mut selections,
12485            );
12486
12487            // Move the text spanned by the row range to be after the last line of the row range
12488            if end_row.0 <= buffer.max_point().row {
12489                let range_to_move =
12490                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12491                let insertion_point = display_map
12492                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12493                    .0;
12494
12495                // Don't move lines across excerpt boundaries
12496                if buffer
12497                    .excerpt_containing(range_to_move.start..insertion_point)
12498                    .is_some()
12499                {
12500                    let mut text = String::from("\n");
12501                    text.extend(buffer.text_for_range(range_to_move.clone()));
12502                    text.pop(); // Drop trailing newline
12503                    edits.push((
12504                        buffer.anchor_after(range_to_move.start)
12505                            ..buffer.anchor_before(range_to_move.end),
12506                        String::new(),
12507                    ));
12508                    let insertion_anchor = buffer.anchor_after(insertion_point);
12509                    edits.push((insertion_anchor..insertion_anchor, text));
12510
12511                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12512
12513                    // Move selections down
12514                    new_selections.extend(contiguous_row_selections.drain(..).map(
12515                        |mut selection| {
12516                            selection.start.row += row_delta;
12517                            selection.end.row += row_delta;
12518                            selection
12519                        },
12520                    ));
12521
12522                    // Move folds down
12523                    unfold_ranges.push(range_to_move.clone());
12524                    for fold in display_map.folds_in_range(
12525                        buffer.anchor_before(range_to_move.start)
12526                            ..buffer.anchor_after(range_to_move.end),
12527                    ) {
12528                        let mut start = fold.range.start.to_point(&buffer);
12529                        let mut end = fold.range.end.to_point(&buffer);
12530                        start.row += row_delta;
12531                        end.row += row_delta;
12532                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12533                    }
12534                }
12535            }
12536
12537            // If we didn't move line(s), preserve the existing selections
12538            new_selections.append(&mut contiguous_row_selections);
12539        }
12540
12541        self.transact(window, cx, |this, window, cx| {
12542            this.unfold_ranges(&unfold_ranges, true, true, cx);
12543            this.buffer.update(cx, |buffer, cx| {
12544                for (range, text) in edits {
12545                    buffer.edit([(range, text)], None, cx);
12546                }
12547            });
12548            this.fold_creases(refold_creases, true, window, cx);
12549            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12550        });
12551    }
12552
12553    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12554        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12555        let text_layout_details = &self.text_layout_details(window);
12556        self.transact(window, cx, |this, window, cx| {
12557            let edits = this.change_selections(Default::default(), window, cx, |s| {
12558                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12559                s.move_with(|display_map, selection| {
12560                    if !selection.is_empty() {
12561                        return;
12562                    }
12563
12564                    let mut head = selection.head();
12565                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12566                    if head.column() == display_map.line_len(head.row()) {
12567                        transpose_offset = display_map
12568                            .buffer_snapshot()
12569                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12570                    }
12571
12572                    if transpose_offset == MultiBufferOffset(0) {
12573                        return;
12574                    }
12575
12576                    *head.column_mut() += 1;
12577                    head = display_map.clip_point(head, Bias::Right);
12578                    let goal = SelectionGoal::HorizontalPosition(
12579                        display_map
12580                            .x_for_display_point(head, text_layout_details)
12581                            .into(),
12582                    );
12583                    selection.collapse_to(head, goal);
12584
12585                    let transpose_start = display_map
12586                        .buffer_snapshot()
12587                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12588                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12589                        let transpose_end = display_map
12590                            .buffer_snapshot()
12591                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12592                        if let Some(ch) = display_map
12593                            .buffer_snapshot()
12594                            .chars_at(transpose_start)
12595                            .next()
12596                        {
12597                            edits.push((transpose_start..transpose_offset, String::new()));
12598                            edits.push((transpose_end..transpose_end, ch.to_string()));
12599                        }
12600                    }
12601                });
12602                edits
12603            });
12604            this.buffer
12605                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12606            let selections = this
12607                .selections
12608                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12609            this.change_selections(Default::default(), window, cx, |s| {
12610                s.select(selections);
12611            });
12612        });
12613    }
12614
12615    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12616        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12617        if self.mode.is_single_line() {
12618            cx.propagate();
12619            return;
12620        }
12621
12622        self.rewrap_impl(RewrapOptions::default(), cx)
12623    }
12624
12625    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12626        let buffer = self.buffer.read(cx).snapshot(cx);
12627        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12628
12629        #[derive(Clone, Debug, PartialEq)]
12630        enum CommentFormat {
12631            /// single line comment, with prefix for line
12632            Line(String),
12633            /// single line within a block comment, with prefix for line
12634            BlockLine(String),
12635            /// a single line of a block comment that includes the initial delimiter
12636            BlockCommentWithStart(BlockCommentConfig),
12637            /// a single line of a block comment that includes the ending delimiter
12638            BlockCommentWithEnd(BlockCommentConfig),
12639        }
12640
12641        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12642        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12643            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12644                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12645                .peekable();
12646
12647            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12648                row
12649            } else {
12650                return Vec::new();
12651            };
12652
12653            let language_settings = buffer.language_settings_at(selection.head(), cx);
12654            let language_scope = buffer.language_scope_at(selection.head());
12655
12656            let indent_and_prefix_for_row =
12657                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12658                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12659                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12660                        &language_scope
12661                    {
12662                        let indent_end = Point::new(row, indent.len);
12663                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12664                        let line_text_after_indent = buffer
12665                            .text_for_range(indent_end..line_end)
12666                            .collect::<String>();
12667
12668                        let is_within_comment_override = buffer
12669                            .language_scope_at(indent_end)
12670                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12671                        let comment_delimiters = if is_within_comment_override {
12672                            // we are within a comment syntax node, but we don't
12673                            // yet know what kind of comment: block, doc or line
12674                            match (
12675                                language_scope.documentation_comment(),
12676                                language_scope.block_comment(),
12677                            ) {
12678                                (Some(config), _) | (_, Some(config))
12679                                    if buffer.contains_str_at(indent_end, &config.start) =>
12680                                {
12681                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12682                                }
12683                                (Some(config), _) | (_, Some(config))
12684                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12685                                {
12686                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12687                                }
12688                                (Some(config), _) | (_, Some(config))
12689                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12690                                {
12691                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12692                                }
12693                                (_, _) => language_scope
12694                                    .line_comment_prefixes()
12695                                    .iter()
12696                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12697                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12698                            }
12699                        } else {
12700                            // we not in an overridden comment node, but we may
12701                            // be within a non-overridden line comment node
12702                            language_scope
12703                                .line_comment_prefixes()
12704                                .iter()
12705                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12706                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12707                        };
12708
12709                        let rewrap_prefix = language_scope
12710                            .rewrap_prefixes()
12711                            .iter()
12712                            .find_map(|prefix_regex| {
12713                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12714                                    if mat.start() == 0 {
12715                                        Some(mat.as_str().to_string())
12716                                    } else {
12717                                        None
12718                                    }
12719                                })
12720                            })
12721                            .flatten();
12722                        (comment_delimiters, rewrap_prefix)
12723                    } else {
12724                        (None, None)
12725                    };
12726                    (indent, comment_prefix, rewrap_prefix)
12727                };
12728
12729            let mut ranges = Vec::new();
12730            let from_empty_selection = selection.is_empty();
12731
12732            let mut current_range_start = first_row;
12733            let mut prev_row = first_row;
12734            let (
12735                mut current_range_indent,
12736                mut current_range_comment_delimiters,
12737                mut current_range_rewrap_prefix,
12738            ) = indent_and_prefix_for_row(first_row);
12739
12740            for row in non_blank_rows_iter.skip(1) {
12741                let has_paragraph_break = row > prev_row + 1;
12742
12743                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12744                    indent_and_prefix_for_row(row);
12745
12746                let has_indent_change = row_indent != current_range_indent;
12747                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12748
12749                let has_boundary_change = has_comment_change
12750                    || row_rewrap_prefix.is_some()
12751                    || (has_indent_change && current_range_comment_delimiters.is_some());
12752
12753                if has_paragraph_break || has_boundary_change {
12754                    ranges.push((
12755                        language_settings.clone(),
12756                        Point::new(current_range_start, 0)
12757                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12758                        current_range_indent,
12759                        current_range_comment_delimiters.clone(),
12760                        current_range_rewrap_prefix.clone(),
12761                        from_empty_selection,
12762                    ));
12763                    current_range_start = row;
12764                    current_range_indent = row_indent;
12765                    current_range_comment_delimiters = row_comment_delimiters;
12766                    current_range_rewrap_prefix = row_rewrap_prefix;
12767                }
12768                prev_row = row;
12769            }
12770
12771            ranges.push((
12772                language_settings.clone(),
12773                Point::new(current_range_start, 0)
12774                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12775                current_range_indent,
12776                current_range_comment_delimiters,
12777                current_range_rewrap_prefix,
12778                from_empty_selection,
12779            ));
12780
12781            ranges
12782        });
12783
12784        let mut edits = Vec::new();
12785        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12786
12787        for (
12788            language_settings,
12789            wrap_range,
12790            mut indent_size,
12791            comment_prefix,
12792            rewrap_prefix,
12793            from_empty_selection,
12794        ) in wrap_ranges
12795        {
12796            let mut start_row = wrap_range.start.row;
12797            let mut end_row = wrap_range.end.row;
12798
12799            // Skip selections that overlap with a range that has already been rewrapped.
12800            let selection_range = start_row..end_row;
12801            if rewrapped_row_ranges
12802                .iter()
12803                .any(|range| range.overlaps(&selection_range))
12804            {
12805                continue;
12806            }
12807
12808            let tab_size = language_settings.tab_size;
12809
12810            let (line_prefix, inside_comment) = match &comment_prefix {
12811                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12812                    (Some(prefix.as_str()), true)
12813                }
12814                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12815                    (Some(prefix.as_ref()), true)
12816                }
12817                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12818                    start: _,
12819                    end: _,
12820                    prefix,
12821                    tab_size,
12822                })) => {
12823                    indent_size.len += tab_size;
12824                    (Some(prefix.as_ref()), true)
12825                }
12826                None => (None, false),
12827            };
12828            let indent_prefix = indent_size.chars().collect::<String>();
12829            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12830
12831            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12832                RewrapBehavior::InComments => inside_comment,
12833                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12834                RewrapBehavior::Anywhere => true,
12835            };
12836
12837            let should_rewrap = options.override_language_settings
12838                || allow_rewrap_based_on_language
12839                || self.hard_wrap.is_some();
12840            if !should_rewrap {
12841                continue;
12842            }
12843
12844            if from_empty_selection {
12845                'expand_upwards: while start_row > 0 {
12846                    let prev_row = start_row - 1;
12847                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12848                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12849                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12850                    {
12851                        start_row = prev_row;
12852                    } else {
12853                        break 'expand_upwards;
12854                    }
12855                }
12856
12857                'expand_downwards: while end_row < buffer.max_point().row {
12858                    let next_row = end_row + 1;
12859                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12860                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12861                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12862                    {
12863                        end_row = next_row;
12864                    } else {
12865                        break 'expand_downwards;
12866                    }
12867                }
12868            }
12869
12870            let start = Point::new(start_row, 0);
12871            let start_offset = ToOffset::to_offset(&start, &buffer);
12872            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12873            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12874            let mut first_line_delimiter = None;
12875            let mut last_line_delimiter = None;
12876            let Some(lines_without_prefixes) = selection_text
12877                .lines()
12878                .enumerate()
12879                .map(|(ix, line)| {
12880                    let line_trimmed = line.trim_start();
12881                    if rewrap_prefix.is_some() && ix > 0 {
12882                        Ok(line_trimmed)
12883                    } else if let Some(
12884                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12885                            start,
12886                            prefix,
12887                            end,
12888                            tab_size,
12889                        })
12890                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12891                            start,
12892                            prefix,
12893                            end,
12894                            tab_size,
12895                        }),
12896                    ) = &comment_prefix
12897                    {
12898                        let line_trimmed = line_trimmed
12899                            .strip_prefix(start.as_ref())
12900                            .map(|s| {
12901                                let mut indent_size = indent_size;
12902                                indent_size.len -= tab_size;
12903                                let indent_prefix: String = indent_size.chars().collect();
12904                                first_line_delimiter = Some((indent_prefix, start));
12905                                s.trim_start()
12906                            })
12907                            .unwrap_or(line_trimmed);
12908                        let line_trimmed = line_trimmed
12909                            .strip_suffix(end.as_ref())
12910                            .map(|s| {
12911                                last_line_delimiter = Some(end);
12912                                s.trim_end()
12913                            })
12914                            .unwrap_or(line_trimmed);
12915                        let line_trimmed = line_trimmed
12916                            .strip_prefix(prefix.as_ref())
12917                            .unwrap_or(line_trimmed);
12918                        Ok(line_trimmed)
12919                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12920                        line_trimmed.strip_prefix(prefix).with_context(|| {
12921                            format!("line did not start with prefix {prefix:?}: {line:?}")
12922                        })
12923                    } else {
12924                        line_trimmed
12925                            .strip_prefix(&line_prefix.trim_start())
12926                            .with_context(|| {
12927                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12928                            })
12929                    }
12930                })
12931                .collect::<Result<Vec<_>, _>>()
12932                .log_err()
12933            else {
12934                continue;
12935            };
12936
12937            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12938                buffer
12939                    .language_settings_at(Point::new(start_row, 0), cx)
12940                    .preferred_line_length as usize
12941            });
12942
12943            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12944                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12945            } else {
12946                line_prefix.clone()
12947            };
12948
12949            let wrapped_text = {
12950                let mut wrapped_text = wrap_with_prefix(
12951                    line_prefix,
12952                    subsequent_lines_prefix,
12953                    lines_without_prefixes.join("\n"),
12954                    wrap_column,
12955                    tab_size,
12956                    options.preserve_existing_whitespace,
12957                );
12958
12959                if let Some((indent, delimiter)) = first_line_delimiter {
12960                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12961                }
12962                if let Some(last_line) = last_line_delimiter {
12963                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12964                }
12965
12966                wrapped_text
12967            };
12968
12969            // TODO: should always use char-based diff while still supporting cursor behavior that
12970            // matches vim.
12971            let mut diff_options = DiffOptions::default();
12972            if options.override_language_settings {
12973                diff_options.max_word_diff_len = 0;
12974                diff_options.max_word_diff_line_count = 0;
12975            } else {
12976                diff_options.max_word_diff_len = usize::MAX;
12977                diff_options.max_word_diff_line_count = usize::MAX;
12978            }
12979
12980            for (old_range, new_text) in
12981                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12982            {
12983                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12984                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12985                edits.push((edit_start..edit_end, new_text));
12986            }
12987
12988            rewrapped_row_ranges.push(start_row..=end_row);
12989        }
12990
12991        self.buffer
12992            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12993    }
12994
12995    pub fn cut_common(
12996        &mut self,
12997        cut_no_selection_line: bool,
12998        window: &mut Window,
12999        cx: &mut Context<Self>,
13000    ) -> ClipboardItem {
13001        let mut text = String::new();
13002        let buffer = self.buffer.read(cx).snapshot(cx);
13003        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13004        let mut clipboard_selections = Vec::with_capacity(selections.len());
13005        {
13006            let max_point = buffer.max_point();
13007            let mut is_first = true;
13008            let mut prev_selection_was_entire_line = false;
13009            for selection in &mut selections {
13010                let is_entire_line =
13011                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13012                if is_entire_line {
13013                    selection.start = Point::new(selection.start.row, 0);
13014                    if !selection.is_empty() && selection.end.column == 0 {
13015                        selection.end = cmp::min(max_point, selection.end);
13016                    } else {
13017                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13018                    }
13019                    selection.goal = SelectionGoal::None;
13020                }
13021                if is_first {
13022                    is_first = false;
13023                } else if !prev_selection_was_entire_line {
13024                    text += "\n";
13025                }
13026                prev_selection_was_entire_line = is_entire_line;
13027                let mut len = 0;
13028                for chunk in buffer.text_for_range(selection.start..selection.end) {
13029                    text.push_str(chunk);
13030                    len += chunk.len();
13031                }
13032
13033                clipboard_selections.push(ClipboardSelection::for_buffer(
13034                    len,
13035                    is_entire_line,
13036                    selection.range(),
13037                    &buffer,
13038                    self.project.as_ref(),
13039                    cx,
13040                ));
13041            }
13042        }
13043
13044        self.transact(window, cx, |this, window, cx| {
13045            this.change_selections(Default::default(), window, cx, |s| {
13046                s.select(selections);
13047            });
13048            this.insert("", window, cx);
13049        });
13050        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13051    }
13052
13053    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13055        let item = self.cut_common(true, window, cx);
13056        cx.write_to_clipboard(item);
13057    }
13058
13059    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13060        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13061        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13062            s.move_with(|snapshot, sel| {
13063                if sel.is_empty() {
13064                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13065                }
13066                if sel.is_empty() {
13067                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13068                }
13069            });
13070        });
13071        let item = self.cut_common(false, window, cx);
13072        cx.set_global(KillRing(item))
13073    }
13074
13075    pub fn kill_ring_yank(
13076        &mut self,
13077        _: &KillRingYank,
13078        window: &mut Window,
13079        cx: &mut Context<Self>,
13080    ) {
13081        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13082        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13083            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13084                (kill_ring.text().to_string(), kill_ring.metadata_json())
13085            } else {
13086                return;
13087            }
13088        } else {
13089            return;
13090        };
13091        self.do_paste(&text, metadata, false, window, cx);
13092    }
13093
13094    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13095        self.do_copy(true, cx);
13096    }
13097
13098    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13099        self.do_copy(false, cx);
13100    }
13101
13102    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13103        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13104        let buffer = self.buffer.read(cx).read(cx);
13105        let mut text = String::new();
13106
13107        let mut clipboard_selections = Vec::with_capacity(selections.len());
13108        {
13109            let max_point = buffer.max_point();
13110            let mut is_first = true;
13111            let mut prev_selection_was_entire_line = false;
13112            for selection in &selections {
13113                let mut start = selection.start;
13114                let mut end = selection.end;
13115                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13116                let mut add_trailing_newline = false;
13117                if is_entire_line {
13118                    start = Point::new(start.row, 0);
13119                    let next_line_start = Point::new(end.row + 1, 0);
13120                    if next_line_start <= max_point {
13121                        end = next_line_start;
13122                    } else {
13123                        // We're on the last line without a trailing newline.
13124                        // Copy to the end of the line and add a newline afterwards.
13125                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13126                        add_trailing_newline = true;
13127                    }
13128                }
13129
13130                let mut trimmed_selections = Vec::new();
13131                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13132                    let row = MultiBufferRow(start.row);
13133                    let first_indent = buffer.indent_size_for_line(row);
13134                    if first_indent.len == 0 || start.column > first_indent.len {
13135                        trimmed_selections.push(start..end);
13136                    } else {
13137                        trimmed_selections.push(
13138                            Point::new(row.0, first_indent.len)
13139                                ..Point::new(row.0, buffer.line_len(row)),
13140                        );
13141                        for row in start.row + 1..=end.row {
13142                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13143                            if row == end.row {
13144                                line_len = end.column;
13145                            }
13146                            if line_len == 0 {
13147                                trimmed_selections
13148                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13149                                continue;
13150                            }
13151                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13152                            if row_indent_size.len >= first_indent.len {
13153                                trimmed_selections.push(
13154                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13155                                );
13156                            } else {
13157                                trimmed_selections.clear();
13158                                trimmed_selections.push(start..end);
13159                                break;
13160                            }
13161                        }
13162                    }
13163                } else {
13164                    trimmed_selections.push(start..end);
13165                }
13166
13167                for trimmed_range in trimmed_selections {
13168                    if is_first {
13169                        is_first = false;
13170                    } else if !prev_selection_was_entire_line {
13171                        text += "\n";
13172                    }
13173                    prev_selection_was_entire_line = is_entire_line;
13174                    let mut len = 0;
13175                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13176                        text.push_str(chunk);
13177                        len += chunk.len();
13178                    }
13179                    if add_trailing_newline {
13180                        text.push('\n');
13181                        len += 1;
13182                    }
13183                    clipboard_selections.push(ClipboardSelection::for_buffer(
13184                        len,
13185                        is_entire_line,
13186                        trimmed_range,
13187                        &buffer,
13188                        self.project.as_ref(),
13189                        cx,
13190                    ));
13191                }
13192            }
13193        }
13194
13195        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13196            text,
13197            clipboard_selections,
13198        ));
13199    }
13200
13201    pub fn do_paste(
13202        &mut self,
13203        text: &String,
13204        clipboard_selections: Option<Vec<ClipboardSelection>>,
13205        handle_entire_lines: bool,
13206        window: &mut Window,
13207        cx: &mut Context<Self>,
13208    ) {
13209        if self.read_only(cx) {
13210            return;
13211        }
13212
13213        let clipboard_text = Cow::Borrowed(text.as_str());
13214
13215        self.transact(window, cx, |this, window, cx| {
13216            let had_active_edit_prediction = this.has_active_edit_prediction();
13217            let display_map = this.display_snapshot(cx);
13218            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13219            let cursor_offset = this
13220                .selections
13221                .last::<MultiBufferOffset>(&display_map)
13222                .head();
13223
13224            if let Some(mut clipboard_selections) = clipboard_selections {
13225                let all_selections_were_entire_line =
13226                    clipboard_selections.iter().all(|s| s.is_entire_line);
13227                let first_selection_indent_column =
13228                    clipboard_selections.first().map(|s| s.first_line_indent);
13229                if clipboard_selections.len() != old_selections.len() {
13230                    clipboard_selections.drain(..);
13231                }
13232                let mut auto_indent_on_paste = true;
13233
13234                this.buffer.update(cx, |buffer, cx| {
13235                    let snapshot = buffer.read(cx);
13236                    auto_indent_on_paste = snapshot
13237                        .language_settings_at(cursor_offset, cx)
13238                        .auto_indent_on_paste;
13239
13240                    let mut start_offset = 0;
13241                    let mut edits = Vec::new();
13242                    let mut original_indent_columns = Vec::new();
13243                    for (ix, selection) in old_selections.iter().enumerate() {
13244                        let to_insert;
13245                        let entire_line;
13246                        let original_indent_column;
13247                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13248                            let end_offset = start_offset + clipboard_selection.len;
13249                            to_insert = &clipboard_text[start_offset..end_offset];
13250                            entire_line = clipboard_selection.is_entire_line;
13251                            start_offset = if entire_line {
13252                                end_offset
13253                            } else {
13254                                end_offset + 1
13255                            };
13256                            original_indent_column = Some(clipboard_selection.first_line_indent);
13257                        } else {
13258                            to_insert = &*clipboard_text;
13259                            entire_line = all_selections_were_entire_line;
13260                            original_indent_column = first_selection_indent_column
13261                        }
13262
13263                        let (range, to_insert) =
13264                            if selection.is_empty() && handle_entire_lines && entire_line {
13265                                // If the corresponding selection was empty when this slice of the
13266                                // clipboard text was written, then the entire line containing the
13267                                // selection was copied. If this selection is also currently empty,
13268                                // then paste the line before the current line of the buffer.
13269                                let column = selection.start.to_point(&snapshot).column as usize;
13270                                let line_start = selection.start - column;
13271                                (line_start..line_start, Cow::Borrowed(to_insert))
13272                            } else {
13273                                let language = snapshot.language_at(selection.head());
13274                                let range = selection.range();
13275                                if let Some(language) = language
13276                                    && language.name() == "Markdown".into()
13277                                {
13278                                    edit_for_markdown_paste(
13279                                        &snapshot,
13280                                        range,
13281                                        to_insert,
13282                                        url::Url::parse(to_insert).ok(),
13283                                    )
13284                                } else {
13285                                    (range, Cow::Borrowed(to_insert))
13286                                }
13287                            };
13288
13289                        edits.push((range, to_insert));
13290                        original_indent_columns.push(original_indent_column);
13291                    }
13292                    drop(snapshot);
13293
13294                    buffer.edit(
13295                        edits,
13296                        if auto_indent_on_paste {
13297                            Some(AutoindentMode::Block {
13298                                original_indent_columns,
13299                            })
13300                        } else {
13301                            None
13302                        },
13303                        cx,
13304                    );
13305                });
13306
13307                let selections = this
13308                    .selections
13309                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13310                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13311            } else {
13312                let url = url::Url::parse(&clipboard_text).ok();
13313
13314                let auto_indent_mode = if !clipboard_text.is_empty() {
13315                    Some(AutoindentMode::Block {
13316                        original_indent_columns: Vec::new(),
13317                    })
13318                } else {
13319                    None
13320                };
13321
13322                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13323                    let snapshot = buffer.snapshot(cx);
13324
13325                    let anchors = old_selections
13326                        .iter()
13327                        .map(|s| {
13328                            let anchor = snapshot.anchor_after(s.head());
13329                            s.map(|_| anchor)
13330                        })
13331                        .collect::<Vec<_>>();
13332
13333                    let mut edits = Vec::new();
13334
13335                    for selection in old_selections.iter() {
13336                        let language = snapshot.language_at(selection.head());
13337                        let range = selection.range();
13338
13339                        let (edit_range, edit_text) = if let Some(language) = language
13340                            && language.name() == "Markdown".into()
13341                        {
13342                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13343                        } else {
13344                            (range, clipboard_text.clone())
13345                        };
13346
13347                        edits.push((edit_range, edit_text));
13348                    }
13349
13350                    drop(snapshot);
13351                    buffer.edit(edits, auto_indent_mode, cx);
13352
13353                    anchors
13354                });
13355
13356                this.change_selections(Default::default(), window, cx, |s| {
13357                    s.select_anchors(selection_anchors);
13358                });
13359            }
13360
13361            //   🤔                 |    ..     | show_in_menu |
13362            // | ..                  |   true        true
13363            // | had_edit_prediction |   false       true
13364
13365            let trigger_in_words =
13366                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13367
13368            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13369        });
13370    }
13371
13372    pub fn diff_clipboard_with_selection(
13373        &mut self,
13374        _: &DiffClipboardWithSelection,
13375        window: &mut Window,
13376        cx: &mut Context<Self>,
13377    ) {
13378        let selections = self
13379            .selections
13380            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13381
13382        if selections.is_empty() {
13383            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13384            return;
13385        };
13386
13387        let clipboard_text = match cx.read_from_clipboard() {
13388            Some(item) => match item.entries().first() {
13389                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13390                _ => None,
13391            },
13392            None => None,
13393        };
13394
13395        let Some(clipboard_text) = clipboard_text else {
13396            log::warn!("Clipboard doesn't contain text.");
13397            return;
13398        };
13399
13400        window.dispatch_action(
13401            Box::new(DiffClipboardWithSelectionData {
13402                clipboard_text,
13403                editor: cx.entity(),
13404            }),
13405            cx,
13406        );
13407    }
13408
13409    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13410        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13411        if let Some(item) = cx.read_from_clipboard() {
13412            let entries = item.entries();
13413
13414            match entries.first() {
13415                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13416                // of all the pasted entries.
13417                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13418                    .do_paste(
13419                        clipboard_string.text(),
13420                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13421                        true,
13422                        window,
13423                        cx,
13424                    ),
13425                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13426            }
13427        }
13428    }
13429
13430    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13431        if self.read_only(cx) {
13432            return;
13433        }
13434
13435        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13436
13437        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13438            if let Some((selections, _)) =
13439                self.selection_history.transaction(transaction_id).cloned()
13440            {
13441                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13442                    s.select_anchors(selections.to_vec());
13443                });
13444            } else {
13445                log::error!(
13446                    "No entry in selection_history found for undo. \
13447                     This may correspond to a bug where undo does not update the selection. \
13448                     If this is occurring, please add details to \
13449                     https://github.com/zed-industries/zed/issues/22692"
13450                );
13451            }
13452            self.request_autoscroll(Autoscroll::fit(), cx);
13453            self.unmark_text(window, cx);
13454            self.refresh_edit_prediction(true, false, window, cx);
13455            cx.emit(EditorEvent::Edited { transaction_id });
13456            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13457        }
13458    }
13459
13460    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13461        if self.read_only(cx) {
13462            return;
13463        }
13464
13465        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13466
13467        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13468            if let Some((_, Some(selections))) =
13469                self.selection_history.transaction(transaction_id).cloned()
13470            {
13471                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13472                    s.select_anchors(selections.to_vec());
13473                });
13474            } else {
13475                log::error!(
13476                    "No entry in selection_history found for redo. \
13477                     This may correspond to a bug where undo does not update the selection. \
13478                     If this is occurring, please add details to \
13479                     https://github.com/zed-industries/zed/issues/22692"
13480                );
13481            }
13482            self.request_autoscroll(Autoscroll::fit(), cx);
13483            self.unmark_text(window, cx);
13484            self.refresh_edit_prediction(true, false, window, cx);
13485            cx.emit(EditorEvent::Edited { transaction_id });
13486        }
13487    }
13488
13489    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13490        self.buffer
13491            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13492    }
13493
13494    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13495        self.buffer
13496            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13497    }
13498
13499    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13500        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13501        self.change_selections(Default::default(), window, cx, |s| {
13502            s.move_with(|map, selection| {
13503                let cursor = if selection.is_empty() {
13504                    movement::left(map, selection.start)
13505                } else {
13506                    selection.start
13507                };
13508                selection.collapse_to(cursor, SelectionGoal::None);
13509            });
13510        })
13511    }
13512
13513    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13514        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13515        self.change_selections(Default::default(), window, cx, |s| {
13516            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13517        })
13518    }
13519
13520    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13521        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13522        self.change_selections(Default::default(), window, cx, |s| {
13523            s.move_with(|map, selection| {
13524                let cursor = if selection.is_empty() {
13525                    movement::right(map, selection.end)
13526                } else {
13527                    selection.end
13528                };
13529                selection.collapse_to(cursor, SelectionGoal::None)
13530            });
13531        })
13532    }
13533
13534    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13535        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13536        self.change_selections(Default::default(), window, cx, |s| {
13537            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13538        });
13539    }
13540
13541    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13542        if self.take_rename(true, window, cx).is_some() {
13543            return;
13544        }
13545
13546        if self.mode.is_single_line() {
13547            cx.propagate();
13548            return;
13549        }
13550
13551        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13552
13553        let text_layout_details = &self.text_layout_details(window);
13554        let selection_count = self.selections.count();
13555        let first_selection = self.selections.first_anchor();
13556
13557        self.change_selections(Default::default(), window, cx, |s| {
13558            s.move_with(|map, selection| {
13559                if !selection.is_empty() {
13560                    selection.goal = SelectionGoal::None;
13561                }
13562                let (cursor, goal) = movement::up(
13563                    map,
13564                    selection.start,
13565                    selection.goal,
13566                    false,
13567                    text_layout_details,
13568                );
13569                selection.collapse_to(cursor, goal);
13570            });
13571        });
13572
13573        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13574        {
13575            cx.propagate();
13576        }
13577    }
13578
13579    pub fn move_up_by_lines(
13580        &mut self,
13581        action: &MoveUpByLines,
13582        window: &mut Window,
13583        cx: &mut Context<Self>,
13584    ) {
13585        if self.take_rename(true, window, cx).is_some() {
13586            return;
13587        }
13588
13589        if self.mode.is_single_line() {
13590            cx.propagate();
13591            return;
13592        }
13593
13594        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13595
13596        let text_layout_details = &self.text_layout_details(window);
13597
13598        self.change_selections(Default::default(), window, cx, |s| {
13599            s.move_with(|map, selection| {
13600                if !selection.is_empty() {
13601                    selection.goal = SelectionGoal::None;
13602                }
13603                let (cursor, goal) = movement::up_by_rows(
13604                    map,
13605                    selection.start,
13606                    action.lines,
13607                    selection.goal,
13608                    false,
13609                    text_layout_details,
13610                );
13611                selection.collapse_to(cursor, goal);
13612            });
13613        })
13614    }
13615
13616    pub fn move_down_by_lines(
13617        &mut self,
13618        action: &MoveDownByLines,
13619        window: &mut Window,
13620        cx: &mut Context<Self>,
13621    ) {
13622        if self.take_rename(true, window, cx).is_some() {
13623            return;
13624        }
13625
13626        if self.mode.is_single_line() {
13627            cx.propagate();
13628            return;
13629        }
13630
13631        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13632
13633        let text_layout_details = &self.text_layout_details(window);
13634
13635        self.change_selections(Default::default(), window, cx, |s| {
13636            s.move_with(|map, selection| {
13637                if !selection.is_empty() {
13638                    selection.goal = SelectionGoal::None;
13639                }
13640                let (cursor, goal) = movement::down_by_rows(
13641                    map,
13642                    selection.start,
13643                    action.lines,
13644                    selection.goal,
13645                    false,
13646                    text_layout_details,
13647                );
13648                selection.collapse_to(cursor, goal);
13649            });
13650        })
13651    }
13652
13653    pub fn select_down_by_lines(
13654        &mut self,
13655        action: &SelectDownByLines,
13656        window: &mut Window,
13657        cx: &mut Context<Self>,
13658    ) {
13659        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13660        let text_layout_details = &self.text_layout_details(window);
13661        self.change_selections(Default::default(), window, cx, |s| {
13662            s.move_heads_with(|map, head, goal| {
13663                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13664            })
13665        })
13666    }
13667
13668    pub fn select_up_by_lines(
13669        &mut self,
13670        action: &SelectUpByLines,
13671        window: &mut Window,
13672        cx: &mut Context<Self>,
13673    ) {
13674        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13675        let text_layout_details = &self.text_layout_details(window);
13676        self.change_selections(Default::default(), window, cx, |s| {
13677            s.move_heads_with(|map, head, goal| {
13678                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13679            })
13680        })
13681    }
13682
13683    pub fn select_page_up(
13684        &mut self,
13685        _: &SelectPageUp,
13686        window: &mut Window,
13687        cx: &mut Context<Self>,
13688    ) {
13689        let Some(row_count) = self.visible_row_count() else {
13690            return;
13691        };
13692
13693        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13694
13695        let text_layout_details = &self.text_layout_details(window);
13696
13697        self.change_selections(Default::default(), window, cx, |s| {
13698            s.move_heads_with(|map, head, goal| {
13699                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13700            })
13701        })
13702    }
13703
13704    pub fn move_page_up(
13705        &mut self,
13706        action: &MovePageUp,
13707        window: &mut Window,
13708        cx: &mut Context<Self>,
13709    ) {
13710        if self.take_rename(true, window, cx).is_some() {
13711            return;
13712        }
13713
13714        if self
13715            .context_menu
13716            .borrow_mut()
13717            .as_mut()
13718            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13719            .unwrap_or(false)
13720        {
13721            return;
13722        }
13723
13724        if matches!(self.mode, EditorMode::SingleLine) {
13725            cx.propagate();
13726            return;
13727        }
13728
13729        let Some(row_count) = self.visible_row_count() else {
13730            return;
13731        };
13732
13733        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13734
13735        let effects = if action.center_cursor {
13736            SelectionEffects::scroll(Autoscroll::center())
13737        } else {
13738            SelectionEffects::default()
13739        };
13740
13741        let text_layout_details = &self.text_layout_details(window);
13742
13743        self.change_selections(effects, window, cx, |s| {
13744            s.move_with(|map, selection| {
13745                if !selection.is_empty() {
13746                    selection.goal = SelectionGoal::None;
13747                }
13748                let (cursor, goal) = movement::up_by_rows(
13749                    map,
13750                    selection.end,
13751                    row_count,
13752                    selection.goal,
13753                    false,
13754                    text_layout_details,
13755                );
13756                selection.collapse_to(cursor, goal);
13757            });
13758        });
13759    }
13760
13761    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13762        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13763        let text_layout_details = &self.text_layout_details(window);
13764        self.change_selections(Default::default(), window, cx, |s| {
13765            s.move_heads_with(|map, head, goal| {
13766                movement::up(map, head, goal, false, text_layout_details)
13767            })
13768        })
13769    }
13770
13771    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13772        self.take_rename(true, window, cx);
13773
13774        if self.mode.is_single_line() {
13775            cx.propagate();
13776            return;
13777        }
13778
13779        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13780
13781        let text_layout_details = &self.text_layout_details(window);
13782        let selection_count = self.selections.count();
13783        let first_selection = self.selections.first_anchor();
13784
13785        self.change_selections(Default::default(), window, cx, |s| {
13786            s.move_with(|map, selection| {
13787                if !selection.is_empty() {
13788                    selection.goal = SelectionGoal::None;
13789                }
13790                let (cursor, goal) = movement::down(
13791                    map,
13792                    selection.end,
13793                    selection.goal,
13794                    false,
13795                    text_layout_details,
13796                );
13797                selection.collapse_to(cursor, goal);
13798            });
13799        });
13800
13801        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13802        {
13803            cx.propagate();
13804        }
13805    }
13806
13807    pub fn select_page_down(
13808        &mut self,
13809        _: &SelectPageDown,
13810        window: &mut Window,
13811        cx: &mut Context<Self>,
13812    ) {
13813        let Some(row_count) = self.visible_row_count() else {
13814            return;
13815        };
13816
13817        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13818
13819        let text_layout_details = &self.text_layout_details(window);
13820
13821        self.change_selections(Default::default(), window, cx, |s| {
13822            s.move_heads_with(|map, head, goal| {
13823                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13824            })
13825        })
13826    }
13827
13828    pub fn move_page_down(
13829        &mut self,
13830        action: &MovePageDown,
13831        window: &mut Window,
13832        cx: &mut Context<Self>,
13833    ) {
13834        if self.take_rename(true, window, cx).is_some() {
13835            return;
13836        }
13837
13838        if self
13839            .context_menu
13840            .borrow_mut()
13841            .as_mut()
13842            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13843            .unwrap_or(false)
13844        {
13845            return;
13846        }
13847
13848        if matches!(self.mode, EditorMode::SingleLine) {
13849            cx.propagate();
13850            return;
13851        }
13852
13853        let Some(row_count) = self.visible_row_count() else {
13854            return;
13855        };
13856
13857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13858
13859        let effects = if action.center_cursor {
13860            SelectionEffects::scroll(Autoscroll::center())
13861        } else {
13862            SelectionEffects::default()
13863        };
13864
13865        let text_layout_details = &self.text_layout_details(window);
13866        self.change_selections(effects, window, cx, |s| {
13867            s.move_with(|map, selection| {
13868                if !selection.is_empty() {
13869                    selection.goal = SelectionGoal::None;
13870                }
13871                let (cursor, goal) = movement::down_by_rows(
13872                    map,
13873                    selection.end,
13874                    row_count,
13875                    selection.goal,
13876                    false,
13877                    text_layout_details,
13878                );
13879                selection.collapse_to(cursor, goal);
13880            });
13881        });
13882    }
13883
13884    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13886        let text_layout_details = &self.text_layout_details(window);
13887        self.change_selections(Default::default(), window, cx, |s| {
13888            s.move_heads_with(|map, head, goal| {
13889                movement::down(map, head, goal, false, text_layout_details)
13890            })
13891        });
13892    }
13893
13894    pub fn context_menu_first(
13895        &mut self,
13896        _: &ContextMenuFirst,
13897        window: &mut Window,
13898        cx: &mut Context<Self>,
13899    ) {
13900        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13901            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13902        }
13903    }
13904
13905    pub fn context_menu_prev(
13906        &mut self,
13907        _: &ContextMenuPrevious,
13908        window: &mut Window,
13909        cx: &mut Context<Self>,
13910    ) {
13911        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13912            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13913        }
13914    }
13915
13916    pub fn context_menu_next(
13917        &mut self,
13918        _: &ContextMenuNext,
13919        window: &mut Window,
13920        cx: &mut Context<Self>,
13921    ) {
13922        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13923            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13924        }
13925    }
13926
13927    pub fn context_menu_last(
13928        &mut self,
13929        _: &ContextMenuLast,
13930        window: &mut Window,
13931        cx: &mut Context<Self>,
13932    ) {
13933        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13934            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13935        }
13936    }
13937
13938    pub fn signature_help_prev(
13939        &mut self,
13940        _: &SignatureHelpPrevious,
13941        _: &mut Window,
13942        cx: &mut Context<Self>,
13943    ) {
13944        if let Some(popover) = self.signature_help_state.popover_mut() {
13945            if popover.current_signature == 0 {
13946                popover.current_signature = popover.signatures.len() - 1;
13947            } else {
13948                popover.current_signature -= 1;
13949            }
13950            cx.notify();
13951        }
13952    }
13953
13954    pub fn signature_help_next(
13955        &mut self,
13956        _: &SignatureHelpNext,
13957        _: &mut Window,
13958        cx: &mut Context<Self>,
13959    ) {
13960        if let Some(popover) = self.signature_help_state.popover_mut() {
13961            if popover.current_signature + 1 == popover.signatures.len() {
13962                popover.current_signature = 0;
13963            } else {
13964                popover.current_signature += 1;
13965            }
13966            cx.notify();
13967        }
13968    }
13969
13970    pub fn move_to_previous_word_start(
13971        &mut self,
13972        _: &MoveToPreviousWordStart,
13973        window: &mut Window,
13974        cx: &mut Context<Self>,
13975    ) {
13976        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13977        self.change_selections(Default::default(), window, cx, |s| {
13978            s.move_cursors_with(|map, head, _| {
13979                (
13980                    movement::previous_word_start(map, head),
13981                    SelectionGoal::None,
13982                )
13983            });
13984        })
13985    }
13986
13987    pub fn move_to_previous_subword_start(
13988        &mut self,
13989        _: &MoveToPreviousSubwordStart,
13990        window: &mut Window,
13991        cx: &mut Context<Self>,
13992    ) {
13993        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13994        self.change_selections(Default::default(), window, cx, |s| {
13995            s.move_cursors_with(|map, head, _| {
13996                (
13997                    movement::previous_subword_start(map, head),
13998                    SelectionGoal::None,
13999                )
14000            });
14001        })
14002    }
14003
14004    pub fn select_to_previous_word_start(
14005        &mut self,
14006        _: &SelectToPreviousWordStart,
14007        window: &mut Window,
14008        cx: &mut Context<Self>,
14009    ) {
14010        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14011        self.change_selections(Default::default(), window, cx, |s| {
14012            s.move_heads_with(|map, head, _| {
14013                (
14014                    movement::previous_word_start(map, head),
14015                    SelectionGoal::None,
14016                )
14017            });
14018        })
14019    }
14020
14021    pub fn select_to_previous_subword_start(
14022        &mut self,
14023        _: &SelectToPreviousSubwordStart,
14024        window: &mut Window,
14025        cx: &mut Context<Self>,
14026    ) {
14027        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14028        self.change_selections(Default::default(), window, cx, |s| {
14029            s.move_heads_with(|map, head, _| {
14030                (
14031                    movement::previous_subword_start(map, head),
14032                    SelectionGoal::None,
14033                )
14034            });
14035        })
14036    }
14037
14038    pub fn delete_to_previous_word_start(
14039        &mut self,
14040        action: &DeleteToPreviousWordStart,
14041        window: &mut Window,
14042        cx: &mut Context<Self>,
14043    ) {
14044        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14045        self.transact(window, cx, |this, window, cx| {
14046            this.select_autoclose_pair(window, cx);
14047            this.change_selections(Default::default(), window, cx, |s| {
14048                s.move_with(|map, selection| {
14049                    if selection.is_empty() {
14050                        let mut cursor = if action.ignore_newlines {
14051                            movement::previous_word_start(map, selection.head())
14052                        } else {
14053                            movement::previous_word_start_or_newline(map, selection.head())
14054                        };
14055                        cursor = movement::adjust_greedy_deletion(
14056                            map,
14057                            selection.head(),
14058                            cursor,
14059                            action.ignore_brackets,
14060                        );
14061                        selection.set_head(cursor, SelectionGoal::None);
14062                    }
14063                });
14064            });
14065            this.insert("", window, cx);
14066        });
14067    }
14068
14069    pub fn delete_to_previous_subword_start(
14070        &mut self,
14071        _: &DeleteToPreviousSubwordStart,
14072        window: &mut Window,
14073        cx: &mut Context<Self>,
14074    ) {
14075        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14076        self.transact(window, cx, |this, window, cx| {
14077            this.select_autoclose_pair(window, cx);
14078            this.change_selections(Default::default(), window, cx, |s| {
14079                s.move_with(|map, selection| {
14080                    if selection.is_empty() {
14081                        let mut cursor = movement::previous_subword_start(map, selection.head());
14082                        cursor =
14083                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14084                        selection.set_head(cursor, SelectionGoal::None);
14085                    }
14086                });
14087            });
14088            this.insert("", window, cx);
14089        });
14090    }
14091
14092    pub fn move_to_next_word_end(
14093        &mut self,
14094        _: &MoveToNextWordEnd,
14095        window: &mut Window,
14096        cx: &mut Context<Self>,
14097    ) {
14098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14099        self.change_selections(Default::default(), window, cx, |s| {
14100            s.move_cursors_with(|map, head, _| {
14101                (movement::next_word_end(map, head), SelectionGoal::None)
14102            });
14103        })
14104    }
14105
14106    pub fn move_to_next_subword_end(
14107        &mut self,
14108        _: &MoveToNextSubwordEnd,
14109        window: &mut Window,
14110        cx: &mut Context<Self>,
14111    ) {
14112        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14113        self.change_selections(Default::default(), window, cx, |s| {
14114            s.move_cursors_with(|map, head, _| {
14115                (movement::next_subword_end(map, head), SelectionGoal::None)
14116            });
14117        })
14118    }
14119
14120    pub fn select_to_next_word_end(
14121        &mut self,
14122        _: &SelectToNextWordEnd,
14123        window: &mut Window,
14124        cx: &mut Context<Self>,
14125    ) {
14126        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14127        self.change_selections(Default::default(), window, cx, |s| {
14128            s.move_heads_with(|map, head, _| {
14129                (movement::next_word_end(map, head), SelectionGoal::None)
14130            });
14131        })
14132    }
14133
14134    pub fn select_to_next_subword_end(
14135        &mut self,
14136        _: &SelectToNextSubwordEnd,
14137        window: &mut Window,
14138        cx: &mut Context<Self>,
14139    ) {
14140        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14141        self.change_selections(Default::default(), window, cx, |s| {
14142            s.move_heads_with(|map, head, _| {
14143                (movement::next_subword_end(map, head), SelectionGoal::None)
14144            });
14145        })
14146    }
14147
14148    pub fn delete_to_next_word_end(
14149        &mut self,
14150        action: &DeleteToNextWordEnd,
14151        window: &mut Window,
14152        cx: &mut Context<Self>,
14153    ) {
14154        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14155        self.transact(window, cx, |this, window, cx| {
14156            this.change_selections(Default::default(), window, cx, |s| {
14157                s.move_with(|map, selection| {
14158                    if selection.is_empty() {
14159                        let mut cursor = if action.ignore_newlines {
14160                            movement::next_word_end(map, selection.head())
14161                        } else {
14162                            movement::next_word_end_or_newline(map, selection.head())
14163                        };
14164                        cursor = movement::adjust_greedy_deletion(
14165                            map,
14166                            selection.head(),
14167                            cursor,
14168                            action.ignore_brackets,
14169                        );
14170                        selection.set_head(cursor, SelectionGoal::None);
14171                    }
14172                });
14173            });
14174            this.insert("", window, cx);
14175        });
14176    }
14177
14178    pub fn delete_to_next_subword_end(
14179        &mut self,
14180        _: &DeleteToNextSubwordEnd,
14181        window: &mut Window,
14182        cx: &mut Context<Self>,
14183    ) {
14184        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14185        self.transact(window, cx, |this, window, cx| {
14186            this.change_selections(Default::default(), window, cx, |s| {
14187                s.move_with(|map, selection| {
14188                    if selection.is_empty() {
14189                        let mut cursor = movement::next_subword_end(map, selection.head());
14190                        cursor =
14191                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14192                        selection.set_head(cursor, SelectionGoal::None);
14193                    }
14194                });
14195            });
14196            this.insert("", window, cx);
14197        });
14198    }
14199
14200    pub fn move_to_beginning_of_line(
14201        &mut self,
14202        action: &MoveToBeginningOfLine,
14203        window: &mut Window,
14204        cx: &mut Context<Self>,
14205    ) {
14206        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14207        self.change_selections(Default::default(), window, cx, |s| {
14208            s.move_cursors_with(|map, head, _| {
14209                (
14210                    movement::indented_line_beginning(
14211                        map,
14212                        head,
14213                        action.stop_at_soft_wraps,
14214                        action.stop_at_indent,
14215                    ),
14216                    SelectionGoal::None,
14217                )
14218            });
14219        })
14220    }
14221
14222    pub fn select_to_beginning_of_line(
14223        &mut self,
14224        action: &SelectToBeginningOfLine,
14225        window: &mut Window,
14226        cx: &mut Context<Self>,
14227    ) {
14228        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14229        self.change_selections(Default::default(), window, cx, |s| {
14230            s.move_heads_with(|map, head, _| {
14231                (
14232                    movement::indented_line_beginning(
14233                        map,
14234                        head,
14235                        action.stop_at_soft_wraps,
14236                        action.stop_at_indent,
14237                    ),
14238                    SelectionGoal::None,
14239                )
14240            });
14241        });
14242    }
14243
14244    pub fn delete_to_beginning_of_line(
14245        &mut self,
14246        action: &DeleteToBeginningOfLine,
14247        window: &mut Window,
14248        cx: &mut Context<Self>,
14249    ) {
14250        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14251        self.transact(window, cx, |this, window, cx| {
14252            this.change_selections(Default::default(), window, cx, |s| {
14253                s.move_with(|_, selection| {
14254                    selection.reversed = true;
14255                });
14256            });
14257
14258            this.select_to_beginning_of_line(
14259                &SelectToBeginningOfLine {
14260                    stop_at_soft_wraps: false,
14261                    stop_at_indent: action.stop_at_indent,
14262                },
14263                window,
14264                cx,
14265            );
14266            this.backspace(&Backspace, window, cx);
14267        });
14268    }
14269
14270    pub fn move_to_end_of_line(
14271        &mut self,
14272        action: &MoveToEndOfLine,
14273        window: &mut Window,
14274        cx: &mut Context<Self>,
14275    ) {
14276        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14277        self.change_selections(Default::default(), window, cx, |s| {
14278            s.move_cursors_with(|map, head, _| {
14279                (
14280                    movement::line_end(map, head, action.stop_at_soft_wraps),
14281                    SelectionGoal::None,
14282                )
14283            });
14284        })
14285    }
14286
14287    pub fn select_to_end_of_line(
14288        &mut self,
14289        action: &SelectToEndOfLine,
14290        window: &mut Window,
14291        cx: &mut Context<Self>,
14292    ) {
14293        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14294        self.change_selections(Default::default(), window, cx, |s| {
14295            s.move_heads_with(|map, head, _| {
14296                (
14297                    movement::line_end(map, head, action.stop_at_soft_wraps),
14298                    SelectionGoal::None,
14299                )
14300            });
14301        })
14302    }
14303
14304    pub fn delete_to_end_of_line(
14305        &mut self,
14306        _: &DeleteToEndOfLine,
14307        window: &mut Window,
14308        cx: &mut Context<Self>,
14309    ) {
14310        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14311        self.transact(window, cx, |this, window, cx| {
14312            this.select_to_end_of_line(
14313                &SelectToEndOfLine {
14314                    stop_at_soft_wraps: false,
14315                },
14316                window,
14317                cx,
14318            );
14319            this.delete(&Delete, window, cx);
14320        });
14321    }
14322
14323    pub fn cut_to_end_of_line(
14324        &mut self,
14325        action: &CutToEndOfLine,
14326        window: &mut Window,
14327        cx: &mut Context<Self>,
14328    ) {
14329        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14330        self.transact(window, cx, |this, window, cx| {
14331            this.select_to_end_of_line(
14332                &SelectToEndOfLine {
14333                    stop_at_soft_wraps: false,
14334                },
14335                window,
14336                cx,
14337            );
14338            if !action.stop_at_newlines {
14339                this.change_selections(Default::default(), window, cx, |s| {
14340                    s.move_with(|_, sel| {
14341                        if sel.is_empty() {
14342                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14343                        }
14344                    });
14345                });
14346            }
14347            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14348            let item = this.cut_common(false, window, cx);
14349            cx.write_to_clipboard(item);
14350        });
14351    }
14352
14353    pub fn move_to_start_of_paragraph(
14354        &mut self,
14355        _: &MoveToStartOfParagraph,
14356        window: &mut Window,
14357        cx: &mut Context<Self>,
14358    ) {
14359        if matches!(self.mode, EditorMode::SingleLine) {
14360            cx.propagate();
14361            return;
14362        }
14363        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14364        self.change_selections(Default::default(), window, cx, |s| {
14365            s.move_with(|map, selection| {
14366                selection.collapse_to(
14367                    movement::start_of_paragraph(map, selection.head(), 1),
14368                    SelectionGoal::None,
14369                )
14370            });
14371        })
14372    }
14373
14374    pub fn move_to_end_of_paragraph(
14375        &mut self,
14376        _: &MoveToEndOfParagraph,
14377        window: &mut Window,
14378        cx: &mut Context<Self>,
14379    ) {
14380        if matches!(self.mode, EditorMode::SingleLine) {
14381            cx.propagate();
14382            return;
14383        }
14384        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14385        self.change_selections(Default::default(), window, cx, |s| {
14386            s.move_with(|map, selection| {
14387                selection.collapse_to(
14388                    movement::end_of_paragraph(map, selection.head(), 1),
14389                    SelectionGoal::None,
14390                )
14391            });
14392        })
14393    }
14394
14395    pub fn select_to_start_of_paragraph(
14396        &mut self,
14397        _: &SelectToStartOfParagraph,
14398        window: &mut Window,
14399        cx: &mut Context<Self>,
14400    ) {
14401        if matches!(self.mode, EditorMode::SingleLine) {
14402            cx.propagate();
14403            return;
14404        }
14405        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14406        self.change_selections(Default::default(), window, cx, |s| {
14407            s.move_heads_with(|map, head, _| {
14408                (
14409                    movement::start_of_paragraph(map, head, 1),
14410                    SelectionGoal::None,
14411                )
14412            });
14413        })
14414    }
14415
14416    pub fn select_to_end_of_paragraph(
14417        &mut self,
14418        _: &SelectToEndOfParagraph,
14419        window: &mut Window,
14420        cx: &mut Context<Self>,
14421    ) {
14422        if matches!(self.mode, EditorMode::SingleLine) {
14423            cx.propagate();
14424            return;
14425        }
14426        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14427        self.change_selections(Default::default(), window, cx, |s| {
14428            s.move_heads_with(|map, head, _| {
14429                (
14430                    movement::end_of_paragraph(map, head, 1),
14431                    SelectionGoal::None,
14432                )
14433            });
14434        })
14435    }
14436
14437    pub fn move_to_start_of_excerpt(
14438        &mut self,
14439        _: &MoveToStartOfExcerpt,
14440        window: &mut Window,
14441        cx: &mut Context<Self>,
14442    ) {
14443        if matches!(self.mode, EditorMode::SingleLine) {
14444            cx.propagate();
14445            return;
14446        }
14447        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14448        self.change_selections(Default::default(), window, cx, |s| {
14449            s.move_with(|map, selection| {
14450                selection.collapse_to(
14451                    movement::start_of_excerpt(
14452                        map,
14453                        selection.head(),
14454                        workspace::searchable::Direction::Prev,
14455                    ),
14456                    SelectionGoal::None,
14457                )
14458            });
14459        })
14460    }
14461
14462    pub fn move_to_start_of_next_excerpt(
14463        &mut self,
14464        _: &MoveToStartOfNextExcerpt,
14465        window: &mut Window,
14466        cx: &mut Context<Self>,
14467    ) {
14468        if matches!(self.mode, EditorMode::SingleLine) {
14469            cx.propagate();
14470            return;
14471        }
14472
14473        self.change_selections(Default::default(), window, cx, |s| {
14474            s.move_with(|map, selection| {
14475                selection.collapse_to(
14476                    movement::start_of_excerpt(
14477                        map,
14478                        selection.head(),
14479                        workspace::searchable::Direction::Next,
14480                    ),
14481                    SelectionGoal::None,
14482                )
14483            });
14484        })
14485    }
14486
14487    pub fn move_to_end_of_excerpt(
14488        &mut self,
14489        _: &MoveToEndOfExcerpt,
14490        window: &mut Window,
14491        cx: &mut Context<Self>,
14492    ) {
14493        if matches!(self.mode, EditorMode::SingleLine) {
14494            cx.propagate();
14495            return;
14496        }
14497        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14498        self.change_selections(Default::default(), window, cx, |s| {
14499            s.move_with(|map, selection| {
14500                selection.collapse_to(
14501                    movement::end_of_excerpt(
14502                        map,
14503                        selection.head(),
14504                        workspace::searchable::Direction::Next,
14505                    ),
14506                    SelectionGoal::None,
14507                )
14508            });
14509        })
14510    }
14511
14512    pub fn move_to_end_of_previous_excerpt(
14513        &mut self,
14514        _: &MoveToEndOfPreviousExcerpt,
14515        window: &mut Window,
14516        cx: &mut Context<Self>,
14517    ) {
14518        if matches!(self.mode, EditorMode::SingleLine) {
14519            cx.propagate();
14520            return;
14521        }
14522        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14523        self.change_selections(Default::default(), window, cx, |s| {
14524            s.move_with(|map, selection| {
14525                selection.collapse_to(
14526                    movement::end_of_excerpt(
14527                        map,
14528                        selection.head(),
14529                        workspace::searchable::Direction::Prev,
14530                    ),
14531                    SelectionGoal::None,
14532                )
14533            });
14534        })
14535    }
14536
14537    pub fn select_to_start_of_excerpt(
14538        &mut self,
14539        _: &SelectToStartOfExcerpt,
14540        window: &mut Window,
14541        cx: &mut Context<Self>,
14542    ) {
14543        if matches!(self.mode, EditorMode::SingleLine) {
14544            cx.propagate();
14545            return;
14546        }
14547        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14548        self.change_selections(Default::default(), window, cx, |s| {
14549            s.move_heads_with(|map, head, _| {
14550                (
14551                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14552                    SelectionGoal::None,
14553                )
14554            });
14555        })
14556    }
14557
14558    pub fn select_to_start_of_next_excerpt(
14559        &mut self,
14560        _: &SelectToStartOfNextExcerpt,
14561        window: &mut Window,
14562        cx: &mut Context<Self>,
14563    ) {
14564        if matches!(self.mode, EditorMode::SingleLine) {
14565            cx.propagate();
14566            return;
14567        }
14568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14569        self.change_selections(Default::default(), window, cx, |s| {
14570            s.move_heads_with(|map, head, _| {
14571                (
14572                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14573                    SelectionGoal::None,
14574                )
14575            });
14576        })
14577    }
14578
14579    pub fn select_to_end_of_excerpt(
14580        &mut self,
14581        _: &SelectToEndOfExcerpt,
14582        window: &mut Window,
14583        cx: &mut Context<Self>,
14584    ) {
14585        if matches!(self.mode, EditorMode::SingleLine) {
14586            cx.propagate();
14587            return;
14588        }
14589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14590        self.change_selections(Default::default(), window, cx, |s| {
14591            s.move_heads_with(|map, head, _| {
14592                (
14593                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14594                    SelectionGoal::None,
14595                )
14596            });
14597        })
14598    }
14599
14600    pub fn select_to_end_of_previous_excerpt(
14601        &mut self,
14602        _: &SelectToEndOfPreviousExcerpt,
14603        window: &mut Window,
14604        cx: &mut Context<Self>,
14605    ) {
14606        if matches!(self.mode, EditorMode::SingleLine) {
14607            cx.propagate();
14608            return;
14609        }
14610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14611        self.change_selections(Default::default(), window, cx, |s| {
14612            s.move_heads_with(|map, head, _| {
14613                (
14614                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14615                    SelectionGoal::None,
14616                )
14617            });
14618        })
14619    }
14620
14621    pub fn move_to_beginning(
14622        &mut self,
14623        _: &MoveToBeginning,
14624        window: &mut Window,
14625        cx: &mut Context<Self>,
14626    ) {
14627        if matches!(self.mode, EditorMode::SingleLine) {
14628            cx.propagate();
14629            return;
14630        }
14631        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14632        self.change_selections(Default::default(), window, cx, |s| {
14633            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14634        });
14635    }
14636
14637    pub fn select_to_beginning(
14638        &mut self,
14639        _: &SelectToBeginning,
14640        window: &mut Window,
14641        cx: &mut Context<Self>,
14642    ) {
14643        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14644        selection.set_head(Point::zero(), SelectionGoal::None);
14645        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14646        self.change_selections(Default::default(), window, cx, |s| {
14647            s.select(vec![selection]);
14648        });
14649    }
14650
14651    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14652        if matches!(self.mode, EditorMode::SingleLine) {
14653            cx.propagate();
14654            return;
14655        }
14656        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14657        let cursor = self.buffer.read(cx).read(cx).len();
14658        self.change_selections(Default::default(), window, cx, |s| {
14659            s.select_ranges(vec![cursor..cursor])
14660        });
14661    }
14662
14663    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14664        self.nav_history = nav_history;
14665    }
14666
14667    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14668        self.nav_history.as_ref()
14669    }
14670
14671    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14672        self.push_to_nav_history(
14673            self.selections.newest_anchor().head(),
14674            None,
14675            false,
14676            true,
14677            cx,
14678        );
14679    }
14680
14681    fn push_to_nav_history(
14682        &mut self,
14683        cursor_anchor: Anchor,
14684        new_position: Option<Point>,
14685        is_deactivate: bool,
14686        always: bool,
14687        cx: &mut Context<Self>,
14688    ) {
14689        if let Some(nav_history) = self.nav_history.as_mut() {
14690            let buffer = self.buffer.read(cx).read(cx);
14691            let cursor_position = cursor_anchor.to_point(&buffer);
14692            let scroll_state = self.scroll_manager.anchor();
14693            let scroll_top_row = scroll_state.top_row(&buffer);
14694            drop(buffer);
14695
14696            if let Some(new_position) = new_position {
14697                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14698                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14699                    return;
14700                }
14701            }
14702
14703            nav_history.push(
14704                Some(NavigationData {
14705                    cursor_anchor,
14706                    cursor_position,
14707                    scroll_anchor: scroll_state,
14708                    scroll_top_row,
14709                }),
14710                cx,
14711            );
14712            cx.emit(EditorEvent::PushedToNavHistory {
14713                anchor: cursor_anchor,
14714                is_deactivate,
14715            })
14716        }
14717    }
14718
14719    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14721        let buffer = self.buffer.read(cx).snapshot(cx);
14722        let mut selection = self
14723            .selections
14724            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14725        selection.set_head(buffer.len(), SelectionGoal::None);
14726        self.change_selections(Default::default(), window, cx, |s| {
14727            s.select(vec![selection]);
14728        });
14729    }
14730
14731    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14732        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14733        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14734            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14735        });
14736    }
14737
14738    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14739        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14740        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14741        let mut selections = self.selections.all::<Point>(&display_map);
14742        let max_point = display_map.buffer_snapshot().max_point();
14743        for selection in &mut selections {
14744            let rows = selection.spanned_rows(true, &display_map);
14745            selection.start = Point::new(rows.start.0, 0);
14746            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14747            selection.reversed = false;
14748        }
14749        self.change_selections(Default::default(), window, cx, |s| {
14750            s.select(selections);
14751        });
14752    }
14753
14754    pub fn split_selection_into_lines(
14755        &mut self,
14756        action: &SplitSelectionIntoLines,
14757        window: &mut Window,
14758        cx: &mut Context<Self>,
14759    ) {
14760        let selections = self
14761            .selections
14762            .all::<Point>(&self.display_snapshot(cx))
14763            .into_iter()
14764            .map(|selection| selection.start..selection.end)
14765            .collect::<Vec<_>>();
14766        self.unfold_ranges(&selections, true, true, cx);
14767
14768        let mut new_selection_ranges = Vec::new();
14769        {
14770            let buffer = self.buffer.read(cx).read(cx);
14771            for selection in selections {
14772                for row in selection.start.row..selection.end.row {
14773                    let line_start = Point::new(row, 0);
14774                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14775
14776                    if action.keep_selections {
14777                        // Keep the selection range for each line
14778                        let selection_start = if row == selection.start.row {
14779                            selection.start
14780                        } else {
14781                            line_start
14782                        };
14783                        new_selection_ranges.push(selection_start..line_end);
14784                    } else {
14785                        // Collapse to cursor at end of line
14786                        new_selection_ranges.push(line_end..line_end);
14787                    }
14788                }
14789
14790                let is_multiline_selection = selection.start.row != selection.end.row;
14791                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14792                // so this action feels more ergonomic when paired with other selection operations
14793                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14794                if !should_skip_last {
14795                    if action.keep_selections {
14796                        if is_multiline_selection {
14797                            let line_start = Point::new(selection.end.row, 0);
14798                            new_selection_ranges.push(line_start..selection.end);
14799                        } else {
14800                            new_selection_ranges.push(selection.start..selection.end);
14801                        }
14802                    } else {
14803                        new_selection_ranges.push(selection.end..selection.end);
14804                    }
14805                }
14806            }
14807        }
14808        self.change_selections(Default::default(), window, cx, |s| {
14809            s.select_ranges(new_selection_ranges);
14810        });
14811    }
14812
14813    pub fn add_selection_above(
14814        &mut self,
14815        action: &AddSelectionAbove,
14816        window: &mut Window,
14817        cx: &mut Context<Self>,
14818    ) {
14819        self.add_selection(true, action.skip_soft_wrap, window, cx);
14820    }
14821
14822    pub fn add_selection_below(
14823        &mut self,
14824        action: &AddSelectionBelow,
14825        window: &mut Window,
14826        cx: &mut Context<Self>,
14827    ) {
14828        self.add_selection(false, action.skip_soft_wrap, window, cx);
14829    }
14830
14831    fn add_selection(
14832        &mut self,
14833        above: bool,
14834        skip_soft_wrap: bool,
14835        window: &mut Window,
14836        cx: &mut Context<Self>,
14837    ) {
14838        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14839
14840        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14841        let all_selections = self.selections.all::<Point>(&display_map);
14842        let text_layout_details = self.text_layout_details(window);
14843
14844        let (mut columnar_selections, new_selections_to_columnarize) = {
14845            if let Some(state) = self.add_selections_state.as_ref() {
14846                let columnar_selection_ids: HashSet<_> = state
14847                    .groups
14848                    .iter()
14849                    .flat_map(|group| group.stack.iter())
14850                    .copied()
14851                    .collect();
14852
14853                all_selections
14854                    .into_iter()
14855                    .partition(|s| columnar_selection_ids.contains(&s.id))
14856            } else {
14857                (Vec::new(), all_selections)
14858            }
14859        };
14860
14861        let mut state = self
14862            .add_selections_state
14863            .take()
14864            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14865
14866        for selection in new_selections_to_columnarize {
14867            let range = selection.display_range(&display_map).sorted();
14868            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14869            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14870            let positions = start_x.min(end_x)..start_x.max(end_x);
14871            let mut stack = Vec::new();
14872            for row in range.start.row().0..=range.end.row().0 {
14873                if let Some(selection) = self.selections.build_columnar_selection(
14874                    &display_map,
14875                    DisplayRow(row),
14876                    &positions,
14877                    selection.reversed,
14878                    &text_layout_details,
14879                ) {
14880                    stack.push(selection.id);
14881                    columnar_selections.push(selection);
14882                }
14883            }
14884            if !stack.is_empty() {
14885                if above {
14886                    stack.reverse();
14887                }
14888                state.groups.push(AddSelectionsGroup { above, stack });
14889            }
14890        }
14891
14892        let mut final_selections = Vec::new();
14893        let end_row = if above {
14894            DisplayRow(0)
14895        } else {
14896            display_map.max_point().row()
14897        };
14898
14899        let mut last_added_item_per_group = HashMap::default();
14900        for group in state.groups.iter_mut() {
14901            if let Some(last_id) = group.stack.last() {
14902                last_added_item_per_group.insert(*last_id, group);
14903            }
14904        }
14905
14906        for selection in columnar_selections {
14907            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14908                if above == group.above {
14909                    let range = selection.display_range(&display_map).sorted();
14910                    debug_assert_eq!(range.start.row(), range.end.row());
14911                    let mut row = range.start.row();
14912                    let positions =
14913                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14914                            Pixels::from(start)..Pixels::from(end)
14915                        } else {
14916                            let start_x =
14917                                display_map.x_for_display_point(range.start, &text_layout_details);
14918                            let end_x =
14919                                display_map.x_for_display_point(range.end, &text_layout_details);
14920                            start_x.min(end_x)..start_x.max(end_x)
14921                        };
14922
14923                    let mut maybe_new_selection = None;
14924                    let direction = if above { -1 } else { 1 };
14925
14926                    while row != end_row {
14927                        if skip_soft_wrap {
14928                            row = display_map
14929                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14930                                .row();
14931                        } else if above {
14932                            row.0 -= 1;
14933                        } else {
14934                            row.0 += 1;
14935                        }
14936
14937                        if let Some(new_selection) = self.selections.build_columnar_selection(
14938                            &display_map,
14939                            row,
14940                            &positions,
14941                            selection.reversed,
14942                            &text_layout_details,
14943                        ) {
14944                            maybe_new_selection = Some(new_selection);
14945                            break;
14946                        }
14947                    }
14948
14949                    if let Some(new_selection) = maybe_new_selection {
14950                        group.stack.push(new_selection.id);
14951                        if above {
14952                            final_selections.push(new_selection);
14953                            final_selections.push(selection);
14954                        } else {
14955                            final_selections.push(selection);
14956                            final_selections.push(new_selection);
14957                        }
14958                    } else {
14959                        final_selections.push(selection);
14960                    }
14961                } else {
14962                    group.stack.pop();
14963                }
14964            } else {
14965                final_selections.push(selection);
14966            }
14967        }
14968
14969        self.change_selections(Default::default(), window, cx, |s| {
14970            s.select(final_selections);
14971        });
14972
14973        let final_selection_ids: HashSet<_> = self
14974            .selections
14975            .all::<Point>(&display_map)
14976            .iter()
14977            .map(|s| s.id)
14978            .collect();
14979        state.groups.retain_mut(|group| {
14980            // selections might get merged above so we remove invalid items from stacks
14981            group.stack.retain(|id| final_selection_ids.contains(id));
14982
14983            // single selection in stack can be treated as initial state
14984            group.stack.len() > 1
14985        });
14986
14987        if !state.groups.is_empty() {
14988            self.add_selections_state = Some(state);
14989        }
14990    }
14991
14992    pub fn insert_snippet_at_selections(
14993        &mut self,
14994        action: &InsertSnippet,
14995        window: &mut Window,
14996        cx: &mut Context<Self>,
14997    ) {
14998        self.try_insert_snippet_at_selections(action, window, cx)
14999            .log_err();
15000    }
15001
15002    fn try_insert_snippet_at_selections(
15003        &mut self,
15004        action: &InsertSnippet,
15005        window: &mut Window,
15006        cx: &mut Context<Self>,
15007    ) -> Result<()> {
15008        let insertion_ranges = self
15009            .selections
15010            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15011            .into_iter()
15012            .map(|selection| selection.range())
15013            .collect_vec();
15014
15015        let snippet = if let Some(snippet_body) = &action.snippet {
15016            if action.language.is_none() && action.name.is_none() {
15017                Snippet::parse(snippet_body)?
15018            } else {
15019                bail!("`snippet` is mutually exclusive with `language` and `name`")
15020            }
15021        } else if let Some(name) = &action.name {
15022            let project = self.project().context("no project")?;
15023            let snippet_store = project.read(cx).snippets().read(cx);
15024            let snippet = snippet_store
15025                .snippets_for(action.language.clone(), cx)
15026                .into_iter()
15027                .find(|snippet| snippet.name == *name)
15028                .context("snippet not found")?;
15029            Snippet::parse(&snippet.body)?
15030        } else {
15031            // todo(andrew): open modal to select snippet
15032            bail!("`name` or `snippet` is required")
15033        };
15034
15035        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15036    }
15037
15038    fn select_match_ranges(
15039        &mut self,
15040        range: Range<MultiBufferOffset>,
15041        reversed: bool,
15042        replace_newest: bool,
15043        auto_scroll: Option<Autoscroll>,
15044        window: &mut Window,
15045        cx: &mut Context<Editor>,
15046    ) {
15047        self.unfold_ranges(
15048            std::slice::from_ref(&range),
15049            false,
15050            auto_scroll.is_some(),
15051            cx,
15052        );
15053        let effects = if let Some(scroll) = auto_scroll {
15054            SelectionEffects::scroll(scroll)
15055        } else {
15056            SelectionEffects::no_scroll()
15057        };
15058        self.change_selections(effects, window, cx, |s| {
15059            if replace_newest {
15060                s.delete(s.newest_anchor().id);
15061            }
15062            if reversed {
15063                s.insert_range(range.end..range.start);
15064            } else {
15065                s.insert_range(range);
15066            }
15067        });
15068    }
15069
15070    pub fn select_next_match_internal(
15071        &mut self,
15072        display_map: &DisplaySnapshot,
15073        replace_newest: bool,
15074        autoscroll: Option<Autoscroll>,
15075        window: &mut Window,
15076        cx: &mut Context<Self>,
15077    ) -> Result<()> {
15078        let buffer = display_map.buffer_snapshot();
15079        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15080        if let Some(mut select_next_state) = self.select_next_state.take() {
15081            let query = &select_next_state.query;
15082            if !select_next_state.done {
15083                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15084                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15085                let mut next_selected_range = None;
15086
15087                let bytes_after_last_selection =
15088                    buffer.bytes_in_range(last_selection.end..buffer.len());
15089                let bytes_before_first_selection =
15090                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15091                let query_matches = query
15092                    .stream_find_iter(bytes_after_last_selection)
15093                    .map(|result| (last_selection.end, result))
15094                    .chain(
15095                        query
15096                            .stream_find_iter(bytes_before_first_selection)
15097                            .map(|result| (MultiBufferOffset(0), result)),
15098                    );
15099
15100                for (start_offset, query_match) in query_matches {
15101                    let query_match = query_match.unwrap(); // can only fail due to I/O
15102                    let offset_range =
15103                        start_offset + query_match.start()..start_offset + query_match.end();
15104
15105                    if !select_next_state.wordwise
15106                        || (!buffer.is_inside_word(offset_range.start, None)
15107                            && !buffer.is_inside_word(offset_range.end, None))
15108                    {
15109                        let idx = selections
15110                            .partition_point(|selection| selection.end <= offset_range.start);
15111                        let overlaps = selections
15112                            .get(idx)
15113                            .map_or(false, |selection| selection.start < offset_range.end);
15114
15115                        if !overlaps {
15116                            next_selected_range = Some(offset_range);
15117                            break;
15118                        }
15119                    }
15120                }
15121
15122                if let Some(next_selected_range) = next_selected_range {
15123                    self.select_match_ranges(
15124                        next_selected_range,
15125                        last_selection.reversed,
15126                        replace_newest,
15127                        autoscroll,
15128                        window,
15129                        cx,
15130                    );
15131                } else {
15132                    select_next_state.done = true;
15133                }
15134            }
15135
15136            self.select_next_state = Some(select_next_state);
15137        } else {
15138            let mut only_carets = true;
15139            let mut same_text_selected = true;
15140            let mut selected_text = None;
15141
15142            let mut selections_iter = selections.iter().peekable();
15143            while let Some(selection) = selections_iter.next() {
15144                if selection.start != selection.end {
15145                    only_carets = false;
15146                }
15147
15148                if same_text_selected {
15149                    if selected_text.is_none() {
15150                        selected_text =
15151                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15152                    }
15153
15154                    if let Some(next_selection) = selections_iter.peek() {
15155                        if next_selection.len() == selection.len() {
15156                            let next_selected_text = buffer
15157                                .text_for_range(next_selection.range())
15158                                .collect::<String>();
15159                            if Some(next_selected_text) != selected_text {
15160                                same_text_selected = false;
15161                                selected_text = None;
15162                            }
15163                        } else {
15164                            same_text_selected = false;
15165                            selected_text = None;
15166                        }
15167                    }
15168                }
15169            }
15170
15171            if only_carets {
15172                for selection in &mut selections {
15173                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15174                    selection.start = word_range.start;
15175                    selection.end = word_range.end;
15176                    selection.goal = SelectionGoal::None;
15177                    selection.reversed = false;
15178                    self.select_match_ranges(
15179                        selection.start..selection.end,
15180                        selection.reversed,
15181                        replace_newest,
15182                        autoscroll,
15183                        window,
15184                        cx,
15185                    );
15186                }
15187
15188                if selections.len() == 1 {
15189                    let selection = selections
15190                        .last()
15191                        .expect("ensured that there's only one selection");
15192                    let query = buffer
15193                        .text_for_range(selection.start..selection.end)
15194                        .collect::<String>();
15195                    let is_empty = query.is_empty();
15196                    let select_state = SelectNextState {
15197                        query: self.build_query(&[query], cx)?,
15198                        wordwise: true,
15199                        done: is_empty,
15200                    };
15201                    self.select_next_state = Some(select_state);
15202                } else {
15203                    self.select_next_state = None;
15204                }
15205            } else if let Some(selected_text) = selected_text {
15206                self.select_next_state = Some(SelectNextState {
15207                    query: self.build_query(&[selected_text], cx)?,
15208                    wordwise: false,
15209                    done: false,
15210                });
15211                self.select_next_match_internal(
15212                    display_map,
15213                    replace_newest,
15214                    autoscroll,
15215                    window,
15216                    cx,
15217                )?;
15218            }
15219        }
15220        Ok(())
15221    }
15222
15223    pub fn select_all_matches(
15224        &mut self,
15225        _action: &SelectAllMatches,
15226        window: &mut Window,
15227        cx: &mut Context<Self>,
15228    ) -> Result<()> {
15229        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15230
15231        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15232
15233        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15234        let Some(select_next_state) = self.select_next_state.as_mut() else {
15235            return Ok(());
15236        };
15237        if select_next_state.done {
15238            return Ok(());
15239        }
15240
15241        let mut new_selections = Vec::new();
15242
15243        let reversed = self
15244            .selections
15245            .oldest::<MultiBufferOffset>(&display_map)
15246            .reversed;
15247        let buffer = display_map.buffer_snapshot();
15248        let query_matches = select_next_state
15249            .query
15250            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15251
15252        for query_match in query_matches.into_iter() {
15253            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15254            let offset_range = if reversed {
15255                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15256            } else {
15257                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15258            };
15259
15260            if !select_next_state.wordwise
15261                || (!buffer.is_inside_word(offset_range.start, None)
15262                    && !buffer.is_inside_word(offset_range.end, None))
15263            {
15264                new_selections.push(offset_range.start..offset_range.end);
15265            }
15266        }
15267
15268        select_next_state.done = true;
15269
15270        if new_selections.is_empty() {
15271            log::error!("bug: new_selections is empty in select_all_matches");
15272            return Ok(());
15273        }
15274
15275        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15276        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15277            selections.select_ranges(new_selections)
15278        });
15279
15280        Ok(())
15281    }
15282
15283    pub fn select_next(
15284        &mut self,
15285        action: &SelectNext,
15286        window: &mut Window,
15287        cx: &mut Context<Self>,
15288    ) -> Result<()> {
15289        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15290        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15291        self.select_next_match_internal(
15292            &display_map,
15293            action.replace_newest,
15294            Some(Autoscroll::newest()),
15295            window,
15296            cx,
15297        )?;
15298        Ok(())
15299    }
15300
15301    pub fn select_previous(
15302        &mut self,
15303        action: &SelectPrevious,
15304        window: &mut Window,
15305        cx: &mut Context<Self>,
15306    ) -> Result<()> {
15307        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15308        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15309        let buffer = display_map.buffer_snapshot();
15310        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15311        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15312            let query = &select_prev_state.query;
15313            if !select_prev_state.done {
15314                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15315                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15316                let mut next_selected_range = None;
15317                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15318                let bytes_before_last_selection =
15319                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15320                let bytes_after_first_selection =
15321                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15322                let query_matches = query
15323                    .stream_find_iter(bytes_before_last_selection)
15324                    .map(|result| (last_selection.start, result))
15325                    .chain(
15326                        query
15327                            .stream_find_iter(bytes_after_first_selection)
15328                            .map(|result| (buffer.len(), result)),
15329                    );
15330                for (end_offset, query_match) in query_matches {
15331                    let query_match = query_match.unwrap(); // can only fail due to I/O
15332                    let offset_range =
15333                        end_offset - query_match.end()..end_offset - query_match.start();
15334
15335                    if !select_prev_state.wordwise
15336                        || (!buffer.is_inside_word(offset_range.start, None)
15337                            && !buffer.is_inside_word(offset_range.end, None))
15338                    {
15339                        next_selected_range = Some(offset_range);
15340                        break;
15341                    }
15342                }
15343
15344                if let Some(next_selected_range) = next_selected_range {
15345                    self.select_match_ranges(
15346                        next_selected_range,
15347                        last_selection.reversed,
15348                        action.replace_newest,
15349                        Some(Autoscroll::newest()),
15350                        window,
15351                        cx,
15352                    );
15353                } else {
15354                    select_prev_state.done = true;
15355                }
15356            }
15357
15358            self.select_prev_state = Some(select_prev_state);
15359        } else {
15360            let mut only_carets = true;
15361            let mut same_text_selected = true;
15362            let mut selected_text = None;
15363
15364            let mut selections_iter = selections.iter().peekable();
15365            while let Some(selection) = selections_iter.next() {
15366                if selection.start != selection.end {
15367                    only_carets = false;
15368                }
15369
15370                if same_text_selected {
15371                    if selected_text.is_none() {
15372                        selected_text =
15373                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15374                    }
15375
15376                    if let Some(next_selection) = selections_iter.peek() {
15377                        if next_selection.len() == selection.len() {
15378                            let next_selected_text = buffer
15379                                .text_for_range(next_selection.range())
15380                                .collect::<String>();
15381                            if Some(next_selected_text) != selected_text {
15382                                same_text_selected = false;
15383                                selected_text = None;
15384                            }
15385                        } else {
15386                            same_text_selected = false;
15387                            selected_text = None;
15388                        }
15389                    }
15390                }
15391            }
15392
15393            if only_carets {
15394                for selection in &mut selections {
15395                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15396                    selection.start = word_range.start;
15397                    selection.end = word_range.end;
15398                    selection.goal = SelectionGoal::None;
15399                    selection.reversed = false;
15400                    self.select_match_ranges(
15401                        selection.start..selection.end,
15402                        selection.reversed,
15403                        action.replace_newest,
15404                        Some(Autoscroll::newest()),
15405                        window,
15406                        cx,
15407                    );
15408                }
15409                if selections.len() == 1 {
15410                    let selection = selections
15411                        .last()
15412                        .expect("ensured that there's only one selection");
15413                    let query = buffer
15414                        .text_for_range(selection.start..selection.end)
15415                        .collect::<String>();
15416                    let is_empty = query.is_empty();
15417                    let select_state = SelectNextState {
15418                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15419                        wordwise: true,
15420                        done: is_empty,
15421                    };
15422                    self.select_prev_state = Some(select_state);
15423                } else {
15424                    self.select_prev_state = None;
15425                }
15426            } else if let Some(selected_text) = selected_text {
15427                self.select_prev_state = Some(SelectNextState {
15428                    query: self
15429                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15430                    wordwise: false,
15431                    done: false,
15432                });
15433                self.select_previous(action, window, cx)?;
15434            }
15435        }
15436        Ok(())
15437    }
15438
15439    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15440    /// setting the case sensitivity based on the global
15441    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15442    /// editor's settings.
15443    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15444    where
15445        I: IntoIterator<Item = P>,
15446        P: AsRef<[u8]>,
15447    {
15448        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15449            || EditorSettings::get_global(cx).search.case_sensitive,
15450            |value| value,
15451        );
15452
15453        let mut builder = AhoCorasickBuilder::new();
15454        builder.ascii_case_insensitive(!case_sensitive);
15455        builder.build(patterns)
15456    }
15457
15458    pub fn find_next_match(
15459        &mut self,
15460        _: &FindNextMatch,
15461        window: &mut Window,
15462        cx: &mut Context<Self>,
15463    ) -> Result<()> {
15464        let selections = self.selections.disjoint_anchors_arc();
15465        match selections.first() {
15466            Some(first) if selections.len() >= 2 => {
15467                self.change_selections(Default::default(), window, cx, |s| {
15468                    s.select_ranges([first.range()]);
15469                });
15470            }
15471            _ => self.select_next(
15472                &SelectNext {
15473                    replace_newest: true,
15474                },
15475                window,
15476                cx,
15477            )?,
15478        }
15479        Ok(())
15480    }
15481
15482    pub fn find_previous_match(
15483        &mut self,
15484        _: &FindPreviousMatch,
15485        window: &mut Window,
15486        cx: &mut Context<Self>,
15487    ) -> Result<()> {
15488        let selections = self.selections.disjoint_anchors_arc();
15489        match selections.last() {
15490            Some(last) if selections.len() >= 2 => {
15491                self.change_selections(Default::default(), window, cx, |s| {
15492                    s.select_ranges([last.range()]);
15493                });
15494            }
15495            _ => self.select_previous(
15496                &SelectPrevious {
15497                    replace_newest: true,
15498                },
15499                window,
15500                cx,
15501            )?,
15502        }
15503        Ok(())
15504    }
15505
15506    pub fn toggle_comments(
15507        &mut self,
15508        action: &ToggleComments,
15509        window: &mut Window,
15510        cx: &mut Context<Self>,
15511    ) {
15512        if self.read_only(cx) {
15513            return;
15514        }
15515        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15516        let text_layout_details = &self.text_layout_details(window);
15517        self.transact(window, cx, |this, window, cx| {
15518            let mut selections = this
15519                .selections
15520                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15521            let mut edits = Vec::new();
15522            let mut selection_edit_ranges = Vec::new();
15523            let mut last_toggled_row = None;
15524            let snapshot = this.buffer.read(cx).read(cx);
15525            let empty_str: Arc<str> = Arc::default();
15526            let mut suffixes_inserted = Vec::new();
15527            let ignore_indent = action.ignore_indent;
15528
15529            fn comment_prefix_range(
15530                snapshot: &MultiBufferSnapshot,
15531                row: MultiBufferRow,
15532                comment_prefix: &str,
15533                comment_prefix_whitespace: &str,
15534                ignore_indent: bool,
15535            ) -> Range<Point> {
15536                let indent_size = if ignore_indent {
15537                    0
15538                } else {
15539                    snapshot.indent_size_for_line(row).len
15540                };
15541
15542                let start = Point::new(row.0, indent_size);
15543
15544                let mut line_bytes = snapshot
15545                    .bytes_in_range(start..snapshot.max_point())
15546                    .flatten()
15547                    .copied();
15548
15549                // If this line currently begins with the line comment prefix, then record
15550                // the range containing the prefix.
15551                if line_bytes
15552                    .by_ref()
15553                    .take(comment_prefix.len())
15554                    .eq(comment_prefix.bytes())
15555                {
15556                    // Include any whitespace that matches the comment prefix.
15557                    let matching_whitespace_len = line_bytes
15558                        .zip(comment_prefix_whitespace.bytes())
15559                        .take_while(|(a, b)| a == b)
15560                        .count() as u32;
15561                    let end = Point::new(
15562                        start.row,
15563                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15564                    );
15565                    start..end
15566                } else {
15567                    start..start
15568                }
15569            }
15570
15571            fn comment_suffix_range(
15572                snapshot: &MultiBufferSnapshot,
15573                row: MultiBufferRow,
15574                comment_suffix: &str,
15575                comment_suffix_has_leading_space: bool,
15576            ) -> Range<Point> {
15577                let end = Point::new(row.0, snapshot.line_len(row));
15578                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15579
15580                let mut line_end_bytes = snapshot
15581                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15582                    .flatten()
15583                    .copied();
15584
15585                let leading_space_len = if suffix_start_column > 0
15586                    && line_end_bytes.next() == Some(b' ')
15587                    && comment_suffix_has_leading_space
15588                {
15589                    1
15590                } else {
15591                    0
15592                };
15593
15594                // If this line currently begins with the line comment prefix, then record
15595                // the range containing the prefix.
15596                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15597                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15598                    start..end
15599                } else {
15600                    end..end
15601                }
15602            }
15603
15604            // TODO: Handle selections that cross excerpts
15605            for selection in &mut selections {
15606                let start_column = snapshot
15607                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15608                    .len;
15609                let language = if let Some(language) =
15610                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15611                {
15612                    language
15613                } else {
15614                    continue;
15615                };
15616
15617                selection_edit_ranges.clear();
15618
15619                // If multiple selections contain a given row, avoid processing that
15620                // row more than once.
15621                let mut start_row = MultiBufferRow(selection.start.row);
15622                if last_toggled_row == Some(start_row) {
15623                    start_row = start_row.next_row();
15624                }
15625                let end_row =
15626                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15627                        MultiBufferRow(selection.end.row - 1)
15628                    } else {
15629                        MultiBufferRow(selection.end.row)
15630                    };
15631                last_toggled_row = Some(end_row);
15632
15633                if start_row > end_row {
15634                    continue;
15635                }
15636
15637                // If the language has line comments, toggle those.
15638                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15639
15640                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15641                if ignore_indent {
15642                    full_comment_prefixes = full_comment_prefixes
15643                        .into_iter()
15644                        .map(|s| Arc::from(s.trim_end()))
15645                        .collect();
15646                }
15647
15648                if !full_comment_prefixes.is_empty() {
15649                    let first_prefix = full_comment_prefixes
15650                        .first()
15651                        .expect("prefixes is non-empty");
15652                    let prefix_trimmed_lengths = full_comment_prefixes
15653                        .iter()
15654                        .map(|p| p.trim_end_matches(' ').len())
15655                        .collect::<SmallVec<[usize; 4]>>();
15656
15657                    let mut all_selection_lines_are_comments = true;
15658
15659                    for row in start_row.0..=end_row.0 {
15660                        let row = MultiBufferRow(row);
15661                        if start_row < end_row && snapshot.is_line_blank(row) {
15662                            continue;
15663                        }
15664
15665                        let prefix_range = full_comment_prefixes
15666                            .iter()
15667                            .zip(prefix_trimmed_lengths.iter().copied())
15668                            .map(|(prefix, trimmed_prefix_len)| {
15669                                comment_prefix_range(
15670                                    snapshot.deref(),
15671                                    row,
15672                                    &prefix[..trimmed_prefix_len],
15673                                    &prefix[trimmed_prefix_len..],
15674                                    ignore_indent,
15675                                )
15676                            })
15677                            .max_by_key(|range| range.end.column - range.start.column)
15678                            .expect("prefixes is non-empty");
15679
15680                        if prefix_range.is_empty() {
15681                            all_selection_lines_are_comments = false;
15682                        }
15683
15684                        selection_edit_ranges.push(prefix_range);
15685                    }
15686
15687                    if all_selection_lines_are_comments {
15688                        edits.extend(
15689                            selection_edit_ranges
15690                                .iter()
15691                                .cloned()
15692                                .map(|range| (range, empty_str.clone())),
15693                        );
15694                    } else {
15695                        let min_column = selection_edit_ranges
15696                            .iter()
15697                            .map(|range| range.start.column)
15698                            .min()
15699                            .unwrap_or(0);
15700                        edits.extend(selection_edit_ranges.iter().map(|range| {
15701                            let position = Point::new(range.start.row, min_column);
15702                            (position..position, first_prefix.clone())
15703                        }));
15704                    }
15705                } else if let Some(BlockCommentConfig {
15706                    start: full_comment_prefix,
15707                    end: comment_suffix,
15708                    ..
15709                }) = language.block_comment()
15710                {
15711                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15712                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15713                    let prefix_range = comment_prefix_range(
15714                        snapshot.deref(),
15715                        start_row,
15716                        comment_prefix,
15717                        comment_prefix_whitespace,
15718                        ignore_indent,
15719                    );
15720                    let suffix_range = comment_suffix_range(
15721                        snapshot.deref(),
15722                        end_row,
15723                        comment_suffix.trim_start_matches(' '),
15724                        comment_suffix.starts_with(' '),
15725                    );
15726
15727                    if prefix_range.is_empty() || suffix_range.is_empty() {
15728                        edits.push((
15729                            prefix_range.start..prefix_range.start,
15730                            full_comment_prefix.clone(),
15731                        ));
15732                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15733                        suffixes_inserted.push((end_row, comment_suffix.len()));
15734                    } else {
15735                        edits.push((prefix_range, empty_str.clone()));
15736                        edits.push((suffix_range, empty_str.clone()));
15737                    }
15738                } else {
15739                    continue;
15740                }
15741            }
15742
15743            drop(snapshot);
15744            this.buffer.update(cx, |buffer, cx| {
15745                buffer.edit(edits, None, cx);
15746            });
15747
15748            // Adjust selections so that they end before any comment suffixes that
15749            // were inserted.
15750            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15751            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15752            let snapshot = this.buffer.read(cx).read(cx);
15753            for selection in &mut selections {
15754                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15755                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15756                        Ordering::Less => {
15757                            suffixes_inserted.next();
15758                            continue;
15759                        }
15760                        Ordering::Greater => break,
15761                        Ordering::Equal => {
15762                            if selection.end.column == snapshot.line_len(row) {
15763                                if selection.is_empty() {
15764                                    selection.start.column -= suffix_len as u32;
15765                                }
15766                                selection.end.column -= suffix_len as u32;
15767                            }
15768                            break;
15769                        }
15770                    }
15771                }
15772            }
15773
15774            drop(snapshot);
15775            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15776
15777            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15778            let selections_on_single_row = selections.windows(2).all(|selections| {
15779                selections[0].start.row == selections[1].start.row
15780                    && selections[0].end.row == selections[1].end.row
15781                    && selections[0].start.row == selections[0].end.row
15782            });
15783            let selections_selecting = selections
15784                .iter()
15785                .any(|selection| selection.start != selection.end);
15786            let advance_downwards = action.advance_downwards
15787                && selections_on_single_row
15788                && !selections_selecting
15789                && !matches!(this.mode, EditorMode::SingleLine);
15790
15791            if advance_downwards {
15792                let snapshot = this.buffer.read(cx).snapshot(cx);
15793
15794                this.change_selections(Default::default(), window, cx, |s| {
15795                    s.move_cursors_with(|display_snapshot, display_point, _| {
15796                        let mut point = display_point.to_point(display_snapshot);
15797                        point.row += 1;
15798                        point = snapshot.clip_point(point, Bias::Left);
15799                        let display_point = point.to_display_point(display_snapshot);
15800                        let goal = SelectionGoal::HorizontalPosition(
15801                            display_snapshot
15802                                .x_for_display_point(display_point, text_layout_details)
15803                                .into(),
15804                        );
15805                        (display_point, goal)
15806                    })
15807                });
15808            }
15809        });
15810    }
15811
15812    pub fn select_enclosing_symbol(
15813        &mut self,
15814        _: &SelectEnclosingSymbol,
15815        window: &mut Window,
15816        cx: &mut Context<Self>,
15817    ) {
15818        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15819
15820        let buffer = self.buffer.read(cx).snapshot(cx);
15821        let old_selections = self
15822            .selections
15823            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15824            .into_boxed_slice();
15825
15826        fn update_selection(
15827            selection: &Selection<MultiBufferOffset>,
15828            buffer_snap: &MultiBufferSnapshot,
15829        ) -> Option<Selection<MultiBufferOffset>> {
15830            let cursor = selection.head();
15831            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15832            for symbol in symbols.iter().rev() {
15833                let start = symbol.range.start.to_offset(buffer_snap);
15834                let end = symbol.range.end.to_offset(buffer_snap);
15835                let new_range = start..end;
15836                if start < selection.start || end > selection.end {
15837                    return Some(Selection {
15838                        id: selection.id,
15839                        start: new_range.start,
15840                        end: new_range.end,
15841                        goal: SelectionGoal::None,
15842                        reversed: selection.reversed,
15843                    });
15844                }
15845            }
15846            None
15847        }
15848
15849        let mut selected_larger_symbol = false;
15850        let new_selections = old_selections
15851            .iter()
15852            .map(|selection| match update_selection(selection, &buffer) {
15853                Some(new_selection) => {
15854                    if new_selection.range() != selection.range() {
15855                        selected_larger_symbol = true;
15856                    }
15857                    new_selection
15858                }
15859                None => selection.clone(),
15860            })
15861            .collect::<Vec<_>>();
15862
15863        if selected_larger_symbol {
15864            self.change_selections(Default::default(), window, cx, |s| {
15865                s.select(new_selections);
15866            });
15867        }
15868    }
15869
15870    pub fn select_larger_syntax_node(
15871        &mut self,
15872        _: &SelectLargerSyntaxNode,
15873        window: &mut Window,
15874        cx: &mut Context<Self>,
15875    ) {
15876        let Some(visible_row_count) = self.visible_row_count() else {
15877            return;
15878        };
15879        let old_selections: Box<[_]> = self
15880            .selections
15881            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15882            .into();
15883        if old_selections.is_empty() {
15884            return;
15885        }
15886
15887        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15888
15889        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15890        let buffer = self.buffer.read(cx).snapshot(cx);
15891
15892        let mut selected_larger_node = false;
15893        let mut new_selections = old_selections
15894            .iter()
15895            .map(|selection| {
15896                let old_range = selection.start..selection.end;
15897
15898                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15899                    // manually select word at selection
15900                    if ["string_content", "inline"].contains(&node.kind()) {
15901                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15902                        // ignore if word is already selected
15903                        if !word_range.is_empty() && old_range != word_range {
15904                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15905                            // only select word if start and end point belongs to same word
15906                            if word_range == last_word_range {
15907                                selected_larger_node = true;
15908                                return Selection {
15909                                    id: selection.id,
15910                                    start: word_range.start,
15911                                    end: word_range.end,
15912                                    goal: SelectionGoal::None,
15913                                    reversed: selection.reversed,
15914                                };
15915                            }
15916                        }
15917                    }
15918                }
15919
15920                let mut new_range = old_range.clone();
15921                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15922                    new_range = range;
15923                    if !node.is_named() {
15924                        continue;
15925                    }
15926                    if !display_map.intersects_fold(new_range.start)
15927                        && !display_map.intersects_fold(new_range.end)
15928                    {
15929                        break;
15930                    }
15931                }
15932
15933                selected_larger_node |= new_range != old_range;
15934                Selection {
15935                    id: selection.id,
15936                    start: new_range.start,
15937                    end: new_range.end,
15938                    goal: SelectionGoal::None,
15939                    reversed: selection.reversed,
15940                }
15941            })
15942            .collect::<Vec<_>>();
15943
15944        if !selected_larger_node {
15945            return; // don't put this call in the history
15946        }
15947
15948        // scroll based on transformation done to the last selection created by the user
15949        let (last_old, last_new) = old_selections
15950            .last()
15951            .zip(new_selections.last().cloned())
15952            .expect("old_selections isn't empty");
15953
15954        // revert selection
15955        let is_selection_reversed = {
15956            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15957            new_selections.last_mut().expect("checked above").reversed =
15958                should_newest_selection_be_reversed;
15959            should_newest_selection_be_reversed
15960        };
15961
15962        if selected_larger_node {
15963            self.select_syntax_node_history.disable_clearing = true;
15964            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15965                s.select(new_selections.clone());
15966            });
15967            self.select_syntax_node_history.disable_clearing = false;
15968        }
15969
15970        let start_row = last_new.start.to_display_point(&display_map).row().0;
15971        let end_row = last_new.end.to_display_point(&display_map).row().0;
15972        let selection_height = end_row - start_row + 1;
15973        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15974
15975        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15976        let scroll_behavior = if fits_on_the_screen {
15977            self.request_autoscroll(Autoscroll::fit(), cx);
15978            SelectSyntaxNodeScrollBehavior::FitSelection
15979        } else if is_selection_reversed {
15980            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15981            SelectSyntaxNodeScrollBehavior::CursorTop
15982        } else {
15983            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15984            SelectSyntaxNodeScrollBehavior::CursorBottom
15985        };
15986
15987        self.select_syntax_node_history.push((
15988            old_selections,
15989            scroll_behavior,
15990            is_selection_reversed,
15991        ));
15992    }
15993
15994    pub fn select_smaller_syntax_node(
15995        &mut self,
15996        _: &SelectSmallerSyntaxNode,
15997        window: &mut Window,
15998        cx: &mut Context<Self>,
15999    ) {
16000        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16001
16002        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16003            self.select_syntax_node_history.pop()
16004        {
16005            if let Some(selection) = selections.last_mut() {
16006                selection.reversed = is_selection_reversed;
16007            }
16008
16009            self.select_syntax_node_history.disable_clearing = true;
16010            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16011                s.select(selections.to_vec());
16012            });
16013            self.select_syntax_node_history.disable_clearing = false;
16014
16015            match scroll_behavior {
16016                SelectSyntaxNodeScrollBehavior::CursorTop => {
16017                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16018                }
16019                SelectSyntaxNodeScrollBehavior::FitSelection => {
16020                    self.request_autoscroll(Autoscroll::fit(), cx);
16021                }
16022                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16023                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16024                }
16025            }
16026        }
16027    }
16028
16029    pub fn unwrap_syntax_node(
16030        &mut self,
16031        _: &UnwrapSyntaxNode,
16032        window: &mut Window,
16033        cx: &mut Context<Self>,
16034    ) {
16035        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16036
16037        let buffer = self.buffer.read(cx).snapshot(cx);
16038        let selections = self
16039            .selections
16040            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16041            .into_iter()
16042            // subtracting the offset requires sorting
16043            .sorted_by_key(|i| i.start);
16044
16045        let full_edits = selections
16046            .into_iter()
16047            .filter_map(|selection| {
16048                let child = if selection.is_empty()
16049                    && let Some((_, ancestor_range)) =
16050                        buffer.syntax_ancestor(selection.start..selection.end)
16051                {
16052                    ancestor_range
16053                } else {
16054                    selection.range()
16055                };
16056
16057                let mut parent = child.clone();
16058                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16059                    parent = ancestor_range;
16060                    if parent.start < child.start || parent.end > child.end {
16061                        break;
16062                    }
16063                }
16064
16065                if parent == child {
16066                    return None;
16067                }
16068                let text = buffer.text_for_range(child).collect::<String>();
16069                Some((selection.id, parent, text))
16070            })
16071            .collect::<Vec<_>>();
16072        if full_edits.is_empty() {
16073            return;
16074        }
16075
16076        self.transact(window, cx, |this, window, cx| {
16077            this.buffer.update(cx, |buffer, cx| {
16078                buffer.edit(
16079                    full_edits
16080                        .iter()
16081                        .map(|(_, p, t)| (p.clone(), t.clone()))
16082                        .collect::<Vec<_>>(),
16083                    None,
16084                    cx,
16085                );
16086            });
16087            this.change_selections(Default::default(), window, cx, |s| {
16088                let mut offset = 0;
16089                let mut selections = vec![];
16090                for (id, parent, text) in full_edits {
16091                    let start = parent.start - offset;
16092                    offset += (parent.end - parent.start) - text.len();
16093                    selections.push(Selection {
16094                        id,
16095                        start,
16096                        end: start + text.len(),
16097                        reversed: false,
16098                        goal: Default::default(),
16099                    });
16100                }
16101                s.select(selections);
16102            });
16103        });
16104    }
16105
16106    pub fn select_next_syntax_node(
16107        &mut self,
16108        _: &SelectNextSyntaxNode,
16109        window: &mut Window,
16110        cx: &mut Context<Self>,
16111    ) {
16112        let old_selections: Box<[_]> = self
16113            .selections
16114            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16115            .into();
16116        if old_selections.is_empty() {
16117            return;
16118        }
16119
16120        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16121
16122        let buffer = self.buffer.read(cx).snapshot(cx);
16123        let mut selected_sibling = false;
16124
16125        let new_selections = old_selections
16126            .iter()
16127            .map(|selection| {
16128                let old_range = selection.start..selection.end;
16129
16130                let old_range =
16131                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16132                let excerpt = buffer.excerpt_containing(old_range.clone());
16133
16134                if let Some(mut excerpt) = excerpt
16135                    && let Some(node) = excerpt
16136                        .buffer()
16137                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16138                {
16139                    let new_range = excerpt.map_range_from_buffer(
16140                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16141                    );
16142                    selected_sibling = true;
16143                    Selection {
16144                        id: selection.id,
16145                        start: new_range.start,
16146                        end: new_range.end,
16147                        goal: SelectionGoal::None,
16148                        reversed: selection.reversed,
16149                    }
16150                } else {
16151                    selection.clone()
16152                }
16153            })
16154            .collect::<Vec<_>>();
16155
16156        if selected_sibling {
16157            self.change_selections(
16158                SelectionEffects::scroll(Autoscroll::fit()),
16159                window,
16160                cx,
16161                |s| {
16162                    s.select(new_selections);
16163                },
16164            );
16165        }
16166    }
16167
16168    pub fn select_prev_syntax_node(
16169        &mut self,
16170        _: &SelectPreviousSyntaxNode,
16171        window: &mut Window,
16172        cx: &mut Context<Self>,
16173    ) {
16174        let old_selections: Box<[_]> = self
16175            .selections
16176            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16177            .into();
16178        if old_selections.is_empty() {
16179            return;
16180        }
16181
16182        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16183
16184        let buffer = self.buffer.read(cx).snapshot(cx);
16185        let mut selected_sibling = false;
16186
16187        let new_selections = old_selections
16188            .iter()
16189            .map(|selection| {
16190                let old_range = selection.start..selection.end;
16191                let old_range =
16192                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16193                let excerpt = buffer.excerpt_containing(old_range.clone());
16194
16195                if let Some(mut excerpt) = excerpt
16196                    && let Some(node) = excerpt
16197                        .buffer()
16198                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16199                {
16200                    let new_range = excerpt.map_range_from_buffer(
16201                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16202                    );
16203                    selected_sibling = true;
16204                    Selection {
16205                        id: selection.id,
16206                        start: new_range.start,
16207                        end: new_range.end,
16208                        goal: SelectionGoal::None,
16209                        reversed: selection.reversed,
16210                    }
16211                } else {
16212                    selection.clone()
16213                }
16214            })
16215            .collect::<Vec<_>>();
16216
16217        if selected_sibling {
16218            self.change_selections(
16219                SelectionEffects::scroll(Autoscroll::fit()),
16220                window,
16221                cx,
16222                |s| {
16223                    s.select(new_selections);
16224                },
16225            );
16226        }
16227    }
16228
16229    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16230        if !EditorSettings::get_global(cx).gutter.runnables {
16231            self.clear_tasks();
16232            return Task::ready(());
16233        }
16234        let project = self.project().map(Entity::downgrade);
16235        let task_sources = self.lsp_task_sources(cx);
16236        let multi_buffer = self.buffer.downgrade();
16237        cx.spawn_in(window, async move |editor, cx| {
16238            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16239            let Some(project) = project.and_then(|p| p.upgrade()) else {
16240                return;
16241            };
16242            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16243                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16244            }) else {
16245                return;
16246            };
16247
16248            let hide_runnables = project
16249                .update(cx, |project, _| project.is_via_collab())
16250                .unwrap_or(true);
16251            if hide_runnables {
16252                return;
16253            }
16254            let new_rows =
16255                cx.background_spawn({
16256                    let snapshot = display_snapshot.clone();
16257                    async move {
16258                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16259                    }
16260                })
16261                    .await;
16262            let Ok(lsp_tasks) =
16263                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16264            else {
16265                return;
16266            };
16267            let lsp_tasks = lsp_tasks.await;
16268
16269            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16270                lsp_tasks
16271                    .into_iter()
16272                    .flat_map(|(kind, tasks)| {
16273                        tasks.into_iter().filter_map(move |(location, task)| {
16274                            Some((kind.clone(), location?, task))
16275                        })
16276                    })
16277                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16278                        let buffer = location.target.buffer;
16279                        let buffer_snapshot = buffer.read(cx).snapshot();
16280                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16281                            |(excerpt_id, snapshot, _)| {
16282                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16283                                    display_snapshot
16284                                        .buffer_snapshot()
16285                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16286                                } else {
16287                                    None
16288                                }
16289                            },
16290                        );
16291                        if let Some(offset) = offset {
16292                            let task_buffer_range =
16293                                location.target.range.to_point(&buffer_snapshot);
16294                            let context_buffer_range =
16295                                task_buffer_range.to_offset(&buffer_snapshot);
16296                            let context_range = BufferOffset(context_buffer_range.start)
16297                                ..BufferOffset(context_buffer_range.end);
16298
16299                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16300                                .or_insert_with(|| RunnableTasks {
16301                                    templates: Vec::new(),
16302                                    offset,
16303                                    column: task_buffer_range.start.column,
16304                                    extra_variables: HashMap::default(),
16305                                    context_range,
16306                                })
16307                                .templates
16308                                .push((kind, task.original_task().clone()));
16309                        }
16310
16311                        acc
16312                    })
16313            }) else {
16314                return;
16315            };
16316
16317            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16318                buffer.language_settings(cx).tasks.prefer_lsp
16319            }) else {
16320                return;
16321            };
16322
16323            let rows = Self::runnable_rows(
16324                project,
16325                display_snapshot,
16326                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16327                new_rows,
16328                cx.clone(),
16329            )
16330            .await;
16331            editor
16332                .update(cx, |editor, _| {
16333                    editor.clear_tasks();
16334                    for (key, mut value) in rows {
16335                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16336                            value.templates.extend(lsp_tasks.templates);
16337                        }
16338
16339                        editor.insert_tasks(key, value);
16340                    }
16341                    for (key, value) in lsp_tasks_by_rows {
16342                        editor.insert_tasks(key, value);
16343                    }
16344                })
16345                .ok();
16346        })
16347    }
16348    fn fetch_runnable_ranges(
16349        snapshot: &DisplaySnapshot,
16350        range: Range<Anchor>,
16351    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16352        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16353    }
16354
16355    fn runnable_rows(
16356        project: Entity<Project>,
16357        snapshot: DisplaySnapshot,
16358        prefer_lsp: bool,
16359        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16360        cx: AsyncWindowContext,
16361    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16362        cx.spawn(async move |cx| {
16363            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16364            for (run_range, mut runnable) in runnable_ranges {
16365                let Some(tasks) = cx
16366                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16367                    .ok()
16368                else {
16369                    continue;
16370                };
16371                let mut tasks = tasks.await;
16372
16373                if prefer_lsp {
16374                    tasks.retain(|(task_kind, _)| {
16375                        !matches!(task_kind, TaskSourceKind::Language { .. })
16376                    });
16377                }
16378                if tasks.is_empty() {
16379                    continue;
16380                }
16381
16382                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16383                let Some(row) = snapshot
16384                    .buffer_snapshot()
16385                    .buffer_line_for_row(MultiBufferRow(point.row))
16386                    .map(|(_, range)| range.start.row)
16387                else {
16388                    continue;
16389                };
16390
16391                let context_range =
16392                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16393                runnable_rows.push((
16394                    (runnable.buffer_id, row),
16395                    RunnableTasks {
16396                        templates: tasks,
16397                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16398                        context_range,
16399                        column: point.column,
16400                        extra_variables: runnable.extra_captures,
16401                    },
16402                ));
16403            }
16404            runnable_rows
16405        })
16406    }
16407
16408    fn templates_with_tags(
16409        project: &Entity<Project>,
16410        runnable: &mut Runnable,
16411        cx: &mut App,
16412    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16413        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16414            let (worktree_id, file) = project
16415                .buffer_for_id(runnable.buffer, cx)
16416                .and_then(|buffer| buffer.read(cx).file())
16417                .map(|file| (file.worktree_id(cx), file.clone()))
16418                .unzip();
16419
16420            (
16421                project.task_store().read(cx).task_inventory().cloned(),
16422                worktree_id,
16423                file,
16424            )
16425        });
16426
16427        let tags = mem::take(&mut runnable.tags);
16428        let language = runnable.language.clone();
16429        cx.spawn(async move |cx| {
16430            let mut templates_with_tags = Vec::new();
16431            if let Some(inventory) = inventory {
16432                for RunnableTag(tag) in tags {
16433                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16434                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16435                    }) else {
16436                        return templates_with_tags;
16437                    };
16438                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16439                        move |(_, template)| {
16440                            template.tags.iter().any(|source_tag| source_tag == &tag)
16441                        },
16442                    ));
16443                }
16444            }
16445            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16446
16447            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16448                // Strongest source wins; if we have worktree tag binding, prefer that to
16449                // global and language bindings;
16450                // if we have a global binding, prefer that to language binding.
16451                let first_mismatch = templates_with_tags
16452                    .iter()
16453                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16454                if let Some(index) = first_mismatch {
16455                    templates_with_tags.truncate(index);
16456                }
16457            }
16458
16459            templates_with_tags
16460        })
16461    }
16462
16463    pub fn move_to_enclosing_bracket(
16464        &mut self,
16465        _: &MoveToEnclosingBracket,
16466        window: &mut Window,
16467        cx: &mut Context<Self>,
16468    ) {
16469        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16470        self.change_selections(Default::default(), window, cx, |s| {
16471            s.move_offsets_with(|snapshot, selection| {
16472                let Some(enclosing_bracket_ranges) =
16473                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16474                else {
16475                    return;
16476                };
16477
16478                let mut best_length = usize::MAX;
16479                let mut best_inside = false;
16480                let mut best_in_bracket_range = false;
16481                let mut best_destination = None;
16482                for (open, close) in enclosing_bracket_ranges {
16483                    let close = close.to_inclusive();
16484                    let length = *close.end() - open.start;
16485                    let inside = selection.start >= open.end && selection.end <= *close.start();
16486                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16487                        || close.contains(&selection.head());
16488
16489                    // If best is next to a bracket and current isn't, skip
16490                    if !in_bracket_range && best_in_bracket_range {
16491                        continue;
16492                    }
16493
16494                    // Prefer smaller lengths unless best is inside and current isn't
16495                    if length > best_length && (best_inside || !inside) {
16496                        continue;
16497                    }
16498
16499                    best_length = length;
16500                    best_inside = inside;
16501                    best_in_bracket_range = in_bracket_range;
16502                    best_destination = Some(
16503                        if close.contains(&selection.start) && close.contains(&selection.end) {
16504                            if inside { open.end } else { open.start }
16505                        } else if inside {
16506                            *close.start()
16507                        } else {
16508                            *close.end()
16509                        },
16510                    );
16511                }
16512
16513                if let Some(destination) = best_destination {
16514                    selection.collapse_to(destination, SelectionGoal::None);
16515                }
16516            })
16517        });
16518    }
16519
16520    pub fn undo_selection(
16521        &mut self,
16522        _: &UndoSelection,
16523        window: &mut Window,
16524        cx: &mut Context<Self>,
16525    ) {
16526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16527        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16528            self.selection_history.mode = SelectionHistoryMode::Undoing;
16529            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16530                this.end_selection(window, cx);
16531                this.change_selections(
16532                    SelectionEffects::scroll(Autoscroll::newest()),
16533                    window,
16534                    cx,
16535                    |s| s.select_anchors(entry.selections.to_vec()),
16536                );
16537            });
16538            self.selection_history.mode = SelectionHistoryMode::Normal;
16539
16540            self.select_next_state = entry.select_next_state;
16541            self.select_prev_state = entry.select_prev_state;
16542            self.add_selections_state = entry.add_selections_state;
16543        }
16544    }
16545
16546    pub fn redo_selection(
16547        &mut self,
16548        _: &RedoSelection,
16549        window: &mut Window,
16550        cx: &mut Context<Self>,
16551    ) {
16552        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16553        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16554            self.selection_history.mode = SelectionHistoryMode::Redoing;
16555            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16556                this.end_selection(window, cx);
16557                this.change_selections(
16558                    SelectionEffects::scroll(Autoscroll::newest()),
16559                    window,
16560                    cx,
16561                    |s| s.select_anchors(entry.selections.to_vec()),
16562                );
16563            });
16564            self.selection_history.mode = SelectionHistoryMode::Normal;
16565
16566            self.select_next_state = entry.select_next_state;
16567            self.select_prev_state = entry.select_prev_state;
16568            self.add_selections_state = entry.add_selections_state;
16569        }
16570    }
16571
16572    pub fn expand_excerpts(
16573        &mut self,
16574        action: &ExpandExcerpts,
16575        _: &mut Window,
16576        cx: &mut Context<Self>,
16577    ) {
16578        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16579    }
16580
16581    pub fn expand_excerpts_down(
16582        &mut self,
16583        action: &ExpandExcerptsDown,
16584        _: &mut Window,
16585        cx: &mut Context<Self>,
16586    ) {
16587        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16588    }
16589
16590    pub fn expand_excerpts_up(
16591        &mut self,
16592        action: &ExpandExcerptsUp,
16593        _: &mut Window,
16594        cx: &mut Context<Self>,
16595    ) {
16596        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16597    }
16598
16599    pub fn expand_excerpts_for_direction(
16600        &mut self,
16601        lines: u32,
16602        direction: ExpandExcerptDirection,
16603
16604        cx: &mut Context<Self>,
16605    ) {
16606        let selections = self.selections.disjoint_anchors_arc();
16607
16608        let lines = if lines == 0 {
16609            EditorSettings::get_global(cx).expand_excerpt_lines
16610        } else {
16611            lines
16612        };
16613
16614        self.buffer.update(cx, |buffer, cx| {
16615            let snapshot = buffer.snapshot(cx);
16616            let mut excerpt_ids = selections
16617                .iter()
16618                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16619                .collect::<Vec<_>>();
16620            excerpt_ids.sort();
16621            excerpt_ids.dedup();
16622            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16623        })
16624    }
16625
16626    pub fn expand_excerpt(
16627        &mut self,
16628        excerpt: ExcerptId,
16629        direction: ExpandExcerptDirection,
16630        window: &mut Window,
16631        cx: &mut Context<Self>,
16632    ) {
16633        let current_scroll_position = self.scroll_position(cx);
16634        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16635        let mut scroll = None;
16636
16637        if direction == ExpandExcerptDirection::Down {
16638            let multi_buffer = self.buffer.read(cx);
16639            let snapshot = multi_buffer.snapshot(cx);
16640            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16641                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16642                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16643            {
16644                let buffer_snapshot = buffer.read(cx).snapshot();
16645                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16646                let last_row = buffer_snapshot.max_point().row;
16647                let lines_below = last_row.saturating_sub(excerpt_end_row);
16648                if lines_below >= lines_to_expand {
16649                    scroll = Some(
16650                        current_scroll_position
16651                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16652                    );
16653                }
16654            }
16655        }
16656        if direction == ExpandExcerptDirection::Up
16657            && self
16658                .buffer
16659                .read(cx)
16660                .snapshot(cx)
16661                .excerpt_before(excerpt)
16662                .is_none()
16663        {
16664            scroll = Some(current_scroll_position);
16665        }
16666
16667        self.buffer.update(cx, |buffer, cx| {
16668            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16669        });
16670
16671        if let Some(new_scroll_position) = scroll {
16672            self.set_scroll_position(new_scroll_position, window, cx);
16673        }
16674    }
16675
16676    pub fn go_to_singleton_buffer_point(
16677        &mut self,
16678        point: Point,
16679        window: &mut Window,
16680        cx: &mut Context<Self>,
16681    ) {
16682        self.go_to_singleton_buffer_range(point..point, window, cx);
16683    }
16684
16685    pub fn go_to_singleton_buffer_range(
16686        &mut self,
16687        range: Range<Point>,
16688        window: &mut Window,
16689        cx: &mut Context<Self>,
16690    ) {
16691        let multibuffer = self.buffer().read(cx);
16692        let Some(buffer) = multibuffer.as_singleton() else {
16693            return;
16694        };
16695        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16696            return;
16697        };
16698        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16699            return;
16700        };
16701        self.change_selections(
16702            SelectionEffects::default().nav_history(true),
16703            window,
16704            cx,
16705            |s| s.select_anchor_ranges([start..end]),
16706        );
16707    }
16708
16709    pub fn go_to_diagnostic(
16710        &mut self,
16711        action: &GoToDiagnostic,
16712        window: &mut Window,
16713        cx: &mut Context<Self>,
16714    ) {
16715        if !self.diagnostics_enabled() {
16716            return;
16717        }
16718        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16719        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16720    }
16721
16722    pub fn go_to_prev_diagnostic(
16723        &mut self,
16724        action: &GoToPreviousDiagnostic,
16725        window: &mut Window,
16726        cx: &mut Context<Self>,
16727    ) {
16728        if !self.diagnostics_enabled() {
16729            return;
16730        }
16731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16732        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16733    }
16734
16735    pub fn go_to_diagnostic_impl(
16736        &mut self,
16737        direction: Direction,
16738        severity: GoToDiagnosticSeverityFilter,
16739        window: &mut Window,
16740        cx: &mut Context<Self>,
16741    ) {
16742        let buffer = self.buffer.read(cx).snapshot(cx);
16743        let selection = self
16744            .selections
16745            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16746
16747        let mut active_group_id = None;
16748        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16749            && active_group.active_range.start.to_offset(&buffer) == selection.start
16750        {
16751            active_group_id = Some(active_group.group_id);
16752        }
16753
16754        fn filtered<'a>(
16755            severity: GoToDiagnosticSeverityFilter,
16756            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16757        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16758            diagnostics
16759                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16760                .filter(|entry| entry.range.start != entry.range.end)
16761                .filter(|entry| !entry.diagnostic.is_unnecessary)
16762        }
16763
16764        let before = filtered(
16765            severity,
16766            buffer
16767                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16768                .filter(|entry| entry.range.start <= selection.start),
16769        );
16770        let after = filtered(
16771            severity,
16772            buffer
16773                .diagnostics_in_range(selection.start..buffer.len())
16774                .filter(|entry| entry.range.start >= selection.start),
16775        );
16776
16777        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16778        if direction == Direction::Prev {
16779            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16780            {
16781                for diagnostic in prev_diagnostics.into_iter().rev() {
16782                    if diagnostic.range.start != selection.start
16783                        || active_group_id
16784                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16785                    {
16786                        found = Some(diagnostic);
16787                        break 'outer;
16788                    }
16789                }
16790            }
16791        } else {
16792            for diagnostic in after.chain(before) {
16793                if diagnostic.range.start != selection.start
16794                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16795                {
16796                    found = Some(diagnostic);
16797                    break;
16798                }
16799            }
16800        }
16801        let Some(next_diagnostic) = found else {
16802            return;
16803        };
16804
16805        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16806        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16807            return;
16808        };
16809        let snapshot = self.snapshot(window, cx);
16810        if snapshot.intersects_fold(next_diagnostic.range.start) {
16811            self.unfold_ranges(
16812                std::slice::from_ref(&next_diagnostic.range),
16813                true,
16814                false,
16815                cx,
16816            );
16817        }
16818        self.change_selections(Default::default(), window, cx, |s| {
16819            s.select_ranges(vec![
16820                next_diagnostic.range.start..next_diagnostic.range.start,
16821            ])
16822        });
16823        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16824        self.refresh_edit_prediction(false, true, window, cx);
16825    }
16826
16827    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16828        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16829        let snapshot = self.snapshot(window, cx);
16830        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16831        self.go_to_hunk_before_or_after_position(
16832            &snapshot,
16833            selection.head(),
16834            Direction::Next,
16835            window,
16836            cx,
16837        );
16838    }
16839
16840    pub fn go_to_hunk_before_or_after_position(
16841        &mut self,
16842        snapshot: &EditorSnapshot,
16843        position: Point,
16844        direction: Direction,
16845        window: &mut Window,
16846        cx: &mut Context<Editor>,
16847    ) {
16848        let row = if direction == Direction::Next {
16849            self.hunk_after_position(snapshot, position)
16850                .map(|hunk| hunk.row_range.start)
16851        } else {
16852            self.hunk_before_position(snapshot, position)
16853        };
16854
16855        if let Some(row) = row {
16856            let destination = Point::new(row.0, 0);
16857            let autoscroll = Autoscroll::center();
16858
16859            self.unfold_ranges(&[destination..destination], false, false, cx);
16860            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16861                s.select_ranges([destination..destination]);
16862            });
16863        }
16864    }
16865
16866    fn hunk_after_position(
16867        &mut self,
16868        snapshot: &EditorSnapshot,
16869        position: Point,
16870    ) -> Option<MultiBufferDiffHunk> {
16871        snapshot
16872            .buffer_snapshot()
16873            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16874            .find(|hunk| hunk.row_range.start.0 > position.row)
16875            .or_else(|| {
16876                snapshot
16877                    .buffer_snapshot()
16878                    .diff_hunks_in_range(Point::zero()..position)
16879                    .find(|hunk| hunk.row_range.end.0 < position.row)
16880            })
16881    }
16882
16883    fn go_to_prev_hunk(
16884        &mut self,
16885        _: &GoToPreviousHunk,
16886        window: &mut Window,
16887        cx: &mut Context<Self>,
16888    ) {
16889        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16890        let snapshot = self.snapshot(window, cx);
16891        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16892        self.go_to_hunk_before_or_after_position(
16893            &snapshot,
16894            selection.head(),
16895            Direction::Prev,
16896            window,
16897            cx,
16898        );
16899    }
16900
16901    fn hunk_before_position(
16902        &mut self,
16903        snapshot: &EditorSnapshot,
16904        position: Point,
16905    ) -> Option<MultiBufferRow> {
16906        snapshot
16907            .buffer_snapshot()
16908            .diff_hunk_before(position)
16909            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16910    }
16911
16912    fn go_to_next_change(
16913        &mut self,
16914        _: &GoToNextChange,
16915        window: &mut Window,
16916        cx: &mut Context<Self>,
16917    ) {
16918        if let Some(selections) = self
16919            .change_list
16920            .next_change(1, Direction::Next)
16921            .map(|s| s.to_vec())
16922        {
16923            self.change_selections(Default::default(), window, cx, |s| {
16924                let map = s.display_snapshot();
16925                s.select_display_ranges(selections.iter().map(|a| {
16926                    let point = a.to_display_point(&map);
16927                    point..point
16928                }))
16929            })
16930        }
16931    }
16932
16933    fn go_to_previous_change(
16934        &mut self,
16935        _: &GoToPreviousChange,
16936        window: &mut Window,
16937        cx: &mut Context<Self>,
16938    ) {
16939        if let Some(selections) = self
16940            .change_list
16941            .next_change(1, Direction::Prev)
16942            .map(|s| s.to_vec())
16943        {
16944            self.change_selections(Default::default(), window, cx, |s| {
16945                let map = s.display_snapshot();
16946                s.select_display_ranges(selections.iter().map(|a| {
16947                    let point = a.to_display_point(&map);
16948                    point..point
16949                }))
16950            })
16951        }
16952    }
16953
16954    pub fn go_to_next_document_highlight(
16955        &mut self,
16956        _: &GoToNextDocumentHighlight,
16957        window: &mut Window,
16958        cx: &mut Context<Self>,
16959    ) {
16960        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16961    }
16962
16963    pub fn go_to_prev_document_highlight(
16964        &mut self,
16965        _: &GoToPreviousDocumentHighlight,
16966        window: &mut Window,
16967        cx: &mut Context<Self>,
16968    ) {
16969        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16970    }
16971
16972    pub fn go_to_document_highlight_before_or_after_position(
16973        &mut self,
16974        direction: Direction,
16975        window: &mut Window,
16976        cx: &mut Context<Editor>,
16977    ) {
16978        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16979        let snapshot = self.snapshot(window, cx);
16980        let buffer = &snapshot.buffer_snapshot();
16981        let position = self
16982            .selections
16983            .newest::<Point>(&snapshot.display_snapshot)
16984            .head();
16985        let anchor_position = buffer.anchor_after(position);
16986
16987        // Get all document highlights (both read and write)
16988        let mut all_highlights = Vec::new();
16989
16990        if let Some((_, read_highlights)) = self
16991            .background_highlights
16992            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16993        {
16994            all_highlights.extend(read_highlights.iter());
16995        }
16996
16997        if let Some((_, write_highlights)) = self
16998            .background_highlights
16999            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17000        {
17001            all_highlights.extend(write_highlights.iter());
17002        }
17003
17004        if all_highlights.is_empty() {
17005            return;
17006        }
17007
17008        // Sort highlights by position
17009        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17010
17011        let target_highlight = match direction {
17012            Direction::Next => {
17013                // Find the first highlight after the current position
17014                all_highlights
17015                    .iter()
17016                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17017            }
17018            Direction::Prev => {
17019                // Find the last highlight before the current position
17020                all_highlights
17021                    .iter()
17022                    .rev()
17023                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17024            }
17025        };
17026
17027        if let Some(highlight) = target_highlight {
17028            let destination = highlight.start.to_point(buffer);
17029            let autoscroll = Autoscroll::center();
17030
17031            self.unfold_ranges(&[destination..destination], false, false, cx);
17032            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17033                s.select_ranges([destination..destination]);
17034            });
17035        }
17036    }
17037
17038    fn go_to_line<T: 'static>(
17039        &mut self,
17040        position: Anchor,
17041        highlight_color: Option<Hsla>,
17042        window: &mut Window,
17043        cx: &mut Context<Self>,
17044    ) {
17045        let snapshot = self.snapshot(window, cx).display_snapshot;
17046        let position = position.to_point(&snapshot.buffer_snapshot());
17047        let start = snapshot
17048            .buffer_snapshot()
17049            .clip_point(Point::new(position.row, 0), Bias::Left);
17050        let end = start + Point::new(1, 0);
17051        let start = snapshot.buffer_snapshot().anchor_before(start);
17052        let end = snapshot.buffer_snapshot().anchor_before(end);
17053
17054        self.highlight_rows::<T>(
17055            start..end,
17056            highlight_color
17057                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17058            Default::default(),
17059            cx,
17060        );
17061
17062        if self.buffer.read(cx).is_singleton() {
17063            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17064        }
17065    }
17066
17067    pub fn go_to_definition(
17068        &mut self,
17069        _: &GoToDefinition,
17070        window: &mut Window,
17071        cx: &mut Context<Self>,
17072    ) -> Task<Result<Navigated>> {
17073        let definition =
17074            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17075        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17076        cx.spawn_in(window, async move |editor, cx| {
17077            if definition.await? == Navigated::Yes {
17078                return Ok(Navigated::Yes);
17079            }
17080            match fallback_strategy {
17081                GoToDefinitionFallback::None => Ok(Navigated::No),
17082                GoToDefinitionFallback::FindAllReferences => {
17083                    match editor.update_in(cx, |editor, window, cx| {
17084                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17085                    })? {
17086                        Some(references) => references.await,
17087                        None => Ok(Navigated::No),
17088                    }
17089                }
17090            }
17091        })
17092    }
17093
17094    pub fn go_to_declaration(
17095        &mut self,
17096        _: &GoToDeclaration,
17097        window: &mut Window,
17098        cx: &mut Context<Self>,
17099    ) -> Task<Result<Navigated>> {
17100        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17101    }
17102
17103    pub fn go_to_declaration_split(
17104        &mut self,
17105        _: &GoToDeclaration,
17106        window: &mut Window,
17107        cx: &mut Context<Self>,
17108    ) -> Task<Result<Navigated>> {
17109        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17110    }
17111
17112    pub fn go_to_implementation(
17113        &mut self,
17114        _: &GoToImplementation,
17115        window: &mut Window,
17116        cx: &mut Context<Self>,
17117    ) -> Task<Result<Navigated>> {
17118        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17119    }
17120
17121    pub fn go_to_implementation_split(
17122        &mut self,
17123        _: &GoToImplementationSplit,
17124        window: &mut Window,
17125        cx: &mut Context<Self>,
17126    ) -> Task<Result<Navigated>> {
17127        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17128    }
17129
17130    pub fn go_to_type_definition(
17131        &mut self,
17132        _: &GoToTypeDefinition,
17133        window: &mut Window,
17134        cx: &mut Context<Self>,
17135    ) -> Task<Result<Navigated>> {
17136        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17137    }
17138
17139    pub fn go_to_definition_split(
17140        &mut self,
17141        _: &GoToDefinitionSplit,
17142        window: &mut Window,
17143        cx: &mut Context<Self>,
17144    ) -> Task<Result<Navigated>> {
17145        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17146    }
17147
17148    pub fn go_to_type_definition_split(
17149        &mut self,
17150        _: &GoToTypeDefinitionSplit,
17151        window: &mut Window,
17152        cx: &mut Context<Self>,
17153    ) -> Task<Result<Navigated>> {
17154        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17155    }
17156
17157    fn go_to_definition_of_kind(
17158        &mut self,
17159        kind: GotoDefinitionKind,
17160        split: bool,
17161        window: &mut Window,
17162        cx: &mut Context<Self>,
17163    ) -> Task<Result<Navigated>> {
17164        let Some(provider) = self.semantics_provider.clone() else {
17165            return Task::ready(Ok(Navigated::No));
17166        };
17167        let head = self
17168            .selections
17169            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17170            .head();
17171        let buffer = self.buffer.read(cx);
17172        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17173            return Task::ready(Ok(Navigated::No));
17174        };
17175        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17176            return Task::ready(Ok(Navigated::No));
17177        };
17178
17179        cx.spawn_in(window, async move |editor, cx| {
17180            let Some(definitions) = definitions.await? else {
17181                return Ok(Navigated::No);
17182            };
17183            let navigated = editor
17184                .update_in(cx, |editor, window, cx| {
17185                    editor.navigate_to_hover_links(
17186                        Some(kind),
17187                        definitions
17188                            .into_iter()
17189                            .filter(|location| {
17190                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17191                            })
17192                            .map(HoverLink::Text)
17193                            .collect::<Vec<_>>(),
17194                        split,
17195                        window,
17196                        cx,
17197                    )
17198                })?
17199                .await?;
17200            anyhow::Ok(navigated)
17201        })
17202    }
17203
17204    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17205        let selection = self.selections.newest_anchor();
17206        let head = selection.head();
17207        let tail = selection.tail();
17208
17209        let Some((buffer, start_position)) =
17210            self.buffer.read(cx).text_anchor_for_position(head, cx)
17211        else {
17212            return;
17213        };
17214
17215        let end_position = if head != tail {
17216            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17217                return;
17218            };
17219            Some(pos)
17220        } else {
17221            None
17222        };
17223
17224        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17225            let url = if let Some(end_pos) = end_position {
17226                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17227            } else {
17228                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17229            };
17230
17231            if let Some(url) = url {
17232                cx.update(|window, cx| {
17233                    if parse_zed_link(&url, cx).is_some() {
17234                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17235                    } else {
17236                        cx.open_url(&url);
17237                    }
17238                })?;
17239            }
17240
17241            anyhow::Ok(())
17242        });
17243
17244        url_finder.detach();
17245    }
17246
17247    pub fn open_selected_filename(
17248        &mut self,
17249        _: &OpenSelectedFilename,
17250        window: &mut Window,
17251        cx: &mut Context<Self>,
17252    ) {
17253        let Some(workspace) = self.workspace() else {
17254            return;
17255        };
17256
17257        let position = self.selections.newest_anchor().head();
17258
17259        let Some((buffer, buffer_position)) =
17260            self.buffer.read(cx).text_anchor_for_position(position, cx)
17261        else {
17262            return;
17263        };
17264
17265        let project = self.project.clone();
17266
17267        cx.spawn_in(window, async move |_, cx| {
17268            let result = find_file(&buffer, project, buffer_position, cx).await;
17269
17270            if let Some((_, path)) = result {
17271                workspace
17272                    .update_in(cx, |workspace, window, cx| {
17273                        workspace.open_resolved_path(path, window, cx)
17274                    })?
17275                    .await?;
17276            }
17277            anyhow::Ok(())
17278        })
17279        .detach();
17280    }
17281
17282    pub(crate) fn navigate_to_hover_links(
17283        &mut self,
17284        kind: Option<GotoDefinitionKind>,
17285        definitions: Vec<HoverLink>,
17286        split: bool,
17287        window: &mut Window,
17288        cx: &mut Context<Editor>,
17289    ) -> Task<Result<Navigated>> {
17290        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17291        let mut first_url_or_file = None;
17292        let definitions: Vec<_> = definitions
17293            .into_iter()
17294            .filter_map(|def| match def {
17295                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17296                HoverLink::InlayHint(lsp_location, server_id) => {
17297                    let computation =
17298                        self.compute_target_location(lsp_location, server_id, window, cx);
17299                    Some(cx.background_spawn(computation))
17300                }
17301                HoverLink::Url(url) => {
17302                    first_url_or_file = Some(Either::Left(url));
17303                    None
17304                }
17305                HoverLink::File(path) => {
17306                    first_url_or_file = Some(Either::Right(path));
17307                    None
17308                }
17309            })
17310            .collect();
17311
17312        let workspace = self.workspace();
17313
17314        cx.spawn_in(window, async move |editor, cx| {
17315            let locations: Vec<Location> = future::join_all(definitions)
17316                .await
17317                .into_iter()
17318                .filter_map(|location| location.transpose())
17319                .collect::<Result<_>>()
17320                .context("location tasks")?;
17321            let mut locations = cx.update(|_, cx| {
17322                locations
17323                    .into_iter()
17324                    .map(|location| {
17325                        let buffer = location.buffer.read(cx);
17326                        (location.buffer, location.range.to_point(buffer))
17327                    })
17328                    .into_group_map()
17329            })?;
17330            let mut num_locations = 0;
17331            for ranges in locations.values_mut() {
17332                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17333                ranges.dedup();
17334                num_locations += ranges.len();
17335            }
17336
17337            if num_locations > 1 {
17338                let tab_kind = match kind {
17339                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17340                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17341                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17342                    Some(GotoDefinitionKind::Type) => "Types",
17343                };
17344                let title = editor
17345                    .update_in(cx, |_, _, cx| {
17346                        let target = locations
17347                            .iter()
17348                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17349                            .map(|(buffer, location)| {
17350                                buffer
17351                                    .read(cx)
17352                                    .text_for_range(location.clone())
17353                                    .collect::<String>()
17354                            })
17355                            .filter(|text| !text.contains('\n'))
17356                            .unique()
17357                            .take(3)
17358                            .join(", ");
17359                        if target.is_empty() {
17360                            tab_kind.to_owned()
17361                        } else {
17362                            format!("{tab_kind} for {target}")
17363                        }
17364                    })
17365                    .context("buffer title")?;
17366
17367                let Some(workspace) = workspace else {
17368                    return Ok(Navigated::No);
17369                };
17370
17371                let opened = workspace
17372                    .update_in(cx, |workspace, window, cx| {
17373                        let allow_preview = PreviewTabsSettings::get_global(cx)
17374                            .enable_preview_multibuffer_from_code_navigation;
17375                        Self::open_locations_in_multibuffer(
17376                            workspace,
17377                            locations,
17378                            title,
17379                            split,
17380                            allow_preview,
17381                            MultibufferSelectionMode::First,
17382                            window,
17383                            cx,
17384                        )
17385                    })
17386                    .is_ok();
17387
17388                anyhow::Ok(Navigated::from_bool(opened))
17389            } else if num_locations == 0 {
17390                // If there is one url or file, open it directly
17391                match first_url_or_file {
17392                    Some(Either::Left(url)) => {
17393                        cx.update(|_, cx| cx.open_url(&url))?;
17394                        Ok(Navigated::Yes)
17395                    }
17396                    Some(Either::Right(path)) => {
17397                        // TODO(andrew): respect preview tab settings
17398                        //               `enable_keep_preview_on_code_navigation` and
17399                        //               `enable_preview_file_from_code_navigation`
17400                        let Some(workspace) = workspace else {
17401                            return Ok(Navigated::No);
17402                        };
17403                        workspace
17404                            .update_in(cx, |workspace, window, cx| {
17405                                workspace.open_resolved_path(path, window, cx)
17406                            })?
17407                            .await?;
17408                        Ok(Navigated::Yes)
17409                    }
17410                    None => Ok(Navigated::No),
17411                }
17412            } else {
17413                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17414                let target_range = target_ranges.first().unwrap().clone();
17415
17416                editor.update_in(cx, |editor, window, cx| {
17417                    let range = target_range.to_point(target_buffer.read(cx));
17418                    let range = editor.range_for_match(&range);
17419                    let range = collapse_multiline_range(range);
17420
17421                    if !split
17422                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17423                    {
17424                        editor.go_to_singleton_buffer_range(range, window, cx);
17425                    } else {
17426                        let Some(workspace) = workspace else {
17427                            return Navigated::No;
17428                        };
17429                        let pane = workspace.read(cx).active_pane().clone();
17430                        window.defer(cx, move |window, cx| {
17431                            let target_editor: Entity<Self> =
17432                                workspace.update(cx, |workspace, cx| {
17433                                    let pane = if split {
17434                                        workspace.adjacent_pane(window, cx)
17435                                    } else {
17436                                        workspace.active_pane().clone()
17437                                    };
17438
17439                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17440                                    let keep_old_preview = preview_tabs_settings
17441                                        .enable_keep_preview_on_code_navigation;
17442                                    let allow_new_preview = preview_tabs_settings
17443                                        .enable_preview_file_from_code_navigation;
17444
17445                                    workspace.open_project_item(
17446                                        pane,
17447                                        target_buffer.clone(),
17448                                        true,
17449                                        true,
17450                                        keep_old_preview,
17451                                        allow_new_preview,
17452                                        window,
17453                                        cx,
17454                                    )
17455                                });
17456                            target_editor.update(cx, |target_editor, cx| {
17457                                // When selecting a definition in a different buffer, disable the nav history
17458                                // to avoid creating a history entry at the previous cursor location.
17459                                pane.update(cx, |pane, _| pane.disable_history());
17460                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17461                                pane.update(cx, |pane, _| pane.enable_history());
17462                            });
17463                        });
17464                    }
17465                    Navigated::Yes
17466                })
17467            }
17468        })
17469    }
17470
17471    fn compute_target_location(
17472        &self,
17473        lsp_location: lsp::Location,
17474        server_id: LanguageServerId,
17475        window: &mut Window,
17476        cx: &mut Context<Self>,
17477    ) -> Task<anyhow::Result<Option<Location>>> {
17478        let Some(project) = self.project.clone() else {
17479            return Task::ready(Ok(None));
17480        };
17481
17482        cx.spawn_in(window, async move |editor, cx| {
17483            let location_task = editor.update(cx, |_, cx| {
17484                project.update(cx, |project, cx| {
17485                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17486                })
17487            })?;
17488            let location = Some({
17489                let target_buffer_handle = location_task.await.context("open local buffer")?;
17490                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17491                    let target_start = target_buffer
17492                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17493                    let target_end = target_buffer
17494                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17495                    target_buffer.anchor_after(target_start)
17496                        ..target_buffer.anchor_before(target_end)
17497                })?;
17498                Location {
17499                    buffer: target_buffer_handle,
17500                    range,
17501                }
17502            });
17503            Ok(location)
17504        })
17505    }
17506
17507    fn go_to_next_reference(
17508        &mut self,
17509        _: &GoToNextReference,
17510        window: &mut Window,
17511        cx: &mut Context<Self>,
17512    ) {
17513        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17514        if let Some(task) = task {
17515            task.detach();
17516        };
17517    }
17518
17519    fn go_to_prev_reference(
17520        &mut self,
17521        _: &GoToPreviousReference,
17522        window: &mut Window,
17523        cx: &mut Context<Self>,
17524    ) {
17525        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17526        if let Some(task) = task {
17527            task.detach();
17528        };
17529    }
17530
17531    pub fn go_to_reference_before_or_after_position(
17532        &mut self,
17533        direction: Direction,
17534        count: usize,
17535        window: &mut Window,
17536        cx: &mut Context<Self>,
17537    ) -> Option<Task<Result<()>>> {
17538        let selection = self.selections.newest_anchor();
17539        let head = selection.head();
17540
17541        let multi_buffer = self.buffer.read(cx);
17542
17543        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17544        let workspace = self.workspace()?;
17545        let project = workspace.read(cx).project().clone();
17546        let references =
17547            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17548        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17549            let Some(locations) = references.await? else {
17550                return Ok(());
17551            };
17552
17553            if locations.is_empty() {
17554                // totally normal - the cursor may be on something which is not
17555                // a symbol (e.g. a keyword)
17556                log::info!("no references found under cursor");
17557                return Ok(());
17558            }
17559
17560            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17561
17562            let (locations, current_location_index) =
17563                multi_buffer.update(cx, |multi_buffer, cx| {
17564                    let mut locations = locations
17565                        .into_iter()
17566                        .filter_map(|loc| {
17567                            let start = multi_buffer.buffer_anchor_to_anchor(
17568                                &loc.buffer,
17569                                loc.range.start,
17570                                cx,
17571                            )?;
17572                            let end = multi_buffer.buffer_anchor_to_anchor(
17573                                &loc.buffer,
17574                                loc.range.end,
17575                                cx,
17576                            )?;
17577                            Some(start..end)
17578                        })
17579                        .collect::<Vec<_>>();
17580
17581                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17582                    // There is an O(n) implementation, but given this list will be
17583                    // small (usually <100 items), the extra O(log(n)) factor isn't
17584                    // worth the (surprisingly large amount of) extra complexity.
17585                    locations
17586                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17587
17588                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17589
17590                    let current_location_index = locations.iter().position(|loc| {
17591                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17592                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17593                    });
17594
17595                    (locations, current_location_index)
17596                })?;
17597
17598            let Some(current_location_index) = current_location_index else {
17599                // This indicates something has gone wrong, because we already
17600                // handle the "no references" case above
17601                log::error!(
17602                    "failed to find current reference under cursor. Total references: {}",
17603                    locations.len()
17604                );
17605                return Ok(());
17606            };
17607
17608            let destination_location_index = match direction {
17609                Direction::Next => (current_location_index + count) % locations.len(),
17610                Direction::Prev => {
17611                    (current_location_index + locations.len() - count % locations.len())
17612                        % locations.len()
17613                }
17614            };
17615
17616            // TODO(cameron): is this needed?
17617            // the thinking is to avoid "jumping to the current location" (avoid
17618            // polluting "jumplist" in vim terms)
17619            if current_location_index == destination_location_index {
17620                return Ok(());
17621            }
17622
17623            let Range { start, end } = locations[destination_location_index];
17624
17625            editor.update_in(cx, |editor, window, cx| {
17626                let effects = SelectionEffects::default();
17627
17628                editor.unfold_ranges(&[start..end], false, false, cx);
17629                editor.change_selections(effects, window, cx, |s| {
17630                    s.select_ranges([start..start]);
17631                });
17632            })?;
17633
17634            Ok(())
17635        }))
17636    }
17637
17638    pub fn find_all_references(
17639        &mut self,
17640        action: &FindAllReferences,
17641        window: &mut Window,
17642        cx: &mut Context<Self>,
17643    ) -> Option<Task<Result<Navigated>>> {
17644        let always_open_multibuffer = action.always_open_multibuffer;
17645        let selection = self.selections.newest_anchor();
17646        let multi_buffer = self.buffer.read(cx);
17647        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17648        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17649        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17650        let head = selection_offset.head();
17651
17652        let head_anchor = multi_buffer_snapshot.anchor_at(
17653            head,
17654            if head < selection_offset.tail() {
17655                Bias::Right
17656            } else {
17657                Bias::Left
17658            },
17659        );
17660
17661        match self
17662            .find_all_references_task_sources
17663            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17664        {
17665            Ok(_) => {
17666                log::info!(
17667                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17668                );
17669                return None;
17670            }
17671            Err(i) => {
17672                self.find_all_references_task_sources.insert(i, head_anchor);
17673            }
17674        }
17675
17676        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17677        let workspace = self.workspace()?;
17678        let project = workspace.read(cx).project().clone();
17679        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17680        Some(cx.spawn_in(window, async move |editor, cx| {
17681            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17682                if let Ok(i) = editor
17683                    .find_all_references_task_sources
17684                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17685                {
17686                    editor.find_all_references_task_sources.remove(i);
17687                }
17688            });
17689
17690            let Some(locations) = references.await? else {
17691                return anyhow::Ok(Navigated::No);
17692            };
17693            let mut locations = cx.update(|_, cx| {
17694                locations
17695                    .into_iter()
17696                    .map(|location| {
17697                        let buffer = location.buffer.read(cx);
17698                        (location.buffer, location.range.to_point(buffer))
17699                    })
17700                    // if special-casing the single-match case, remove ranges
17701                    // that intersect current selection
17702                    .filter(|(location_buffer, location)| {
17703                        if always_open_multibuffer || &buffer != location_buffer {
17704                            return true;
17705                        }
17706
17707                        !location.contains_inclusive(&selection_point.range())
17708                    })
17709                    .into_group_map()
17710            })?;
17711            if locations.is_empty() {
17712                return anyhow::Ok(Navigated::No);
17713            }
17714            for ranges in locations.values_mut() {
17715                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17716                ranges.dedup();
17717            }
17718            let mut num_locations = 0;
17719            for ranges in locations.values_mut() {
17720                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17721                ranges.dedup();
17722                num_locations += ranges.len();
17723            }
17724
17725            if num_locations == 1 && !always_open_multibuffer {
17726                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17727                let target_range = target_ranges.first().unwrap().clone();
17728
17729                return editor.update_in(cx, |editor, window, cx| {
17730                    let range = target_range.to_point(target_buffer.read(cx));
17731                    let range = editor.range_for_match(&range);
17732                    let range = range.start..range.start;
17733
17734                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17735                        editor.go_to_singleton_buffer_range(range, window, cx);
17736                    } else {
17737                        let pane = workspace.read(cx).active_pane().clone();
17738                        window.defer(cx, move |window, cx| {
17739                            let target_editor: Entity<Self> =
17740                                workspace.update(cx, |workspace, cx| {
17741                                    let pane = workspace.active_pane().clone();
17742
17743                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17744                                    let keep_old_preview = preview_tabs_settings
17745                                        .enable_keep_preview_on_code_navigation;
17746                                    let allow_new_preview = preview_tabs_settings
17747                                        .enable_preview_file_from_code_navigation;
17748
17749                                    workspace.open_project_item(
17750                                        pane,
17751                                        target_buffer.clone(),
17752                                        true,
17753                                        true,
17754                                        keep_old_preview,
17755                                        allow_new_preview,
17756                                        window,
17757                                        cx,
17758                                    )
17759                                });
17760                            target_editor.update(cx, |target_editor, cx| {
17761                                // When selecting a definition in a different buffer, disable the nav history
17762                                // to avoid creating a history entry at the previous cursor location.
17763                                pane.update(cx, |pane, _| pane.disable_history());
17764                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17765                                pane.update(cx, |pane, _| pane.enable_history());
17766                            });
17767                        });
17768                    }
17769                    Navigated::No
17770                });
17771            }
17772
17773            workspace.update_in(cx, |workspace, window, cx| {
17774                let target = locations
17775                    .iter()
17776                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17777                    .map(|(buffer, location)| {
17778                        buffer
17779                            .read(cx)
17780                            .text_for_range(location.clone())
17781                            .collect::<String>()
17782                    })
17783                    .filter(|text| !text.contains('\n'))
17784                    .unique()
17785                    .take(3)
17786                    .join(", ");
17787                let title = if target.is_empty() {
17788                    "References".to_owned()
17789                } else {
17790                    format!("References to {target}")
17791                };
17792                let allow_preview = PreviewTabsSettings::get_global(cx)
17793                    .enable_preview_multibuffer_from_code_navigation;
17794                Self::open_locations_in_multibuffer(
17795                    workspace,
17796                    locations,
17797                    title,
17798                    false,
17799                    allow_preview,
17800                    MultibufferSelectionMode::First,
17801                    window,
17802                    cx,
17803                );
17804                Navigated::Yes
17805            })
17806        }))
17807    }
17808
17809    /// Opens a multibuffer with the given project locations in it.
17810    pub fn open_locations_in_multibuffer(
17811        workspace: &mut Workspace,
17812        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17813        title: String,
17814        split: bool,
17815        allow_preview: bool,
17816        multibuffer_selection_mode: MultibufferSelectionMode,
17817        window: &mut Window,
17818        cx: &mut Context<Workspace>,
17819    ) {
17820        if locations.is_empty() {
17821            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17822            return;
17823        }
17824
17825        let capability = workspace.project().read(cx).capability();
17826        let mut ranges = <Vec<Range<Anchor>>>::new();
17827
17828        // a key to find existing multibuffer editors with the same set of locations
17829        // to prevent us from opening more and more multibuffer tabs for searches and the like
17830        let mut key = (title.clone(), vec![]);
17831        let excerpt_buffer = cx.new(|cx| {
17832            let key = &mut key.1;
17833            let mut multibuffer = MultiBuffer::new(capability);
17834            for (buffer, mut ranges_for_buffer) in locations {
17835                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17836                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17837                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17838                    PathKey::for_buffer(&buffer, cx),
17839                    buffer.clone(),
17840                    ranges_for_buffer,
17841                    multibuffer_context_lines(cx),
17842                    cx,
17843                );
17844                ranges.extend(new_ranges)
17845            }
17846
17847            multibuffer.with_title(title)
17848        });
17849        let existing = workspace.active_pane().update(cx, |pane, cx| {
17850            pane.items()
17851                .filter_map(|item| item.downcast::<Editor>())
17852                .find(|editor| {
17853                    editor
17854                        .read(cx)
17855                        .lookup_key
17856                        .as_ref()
17857                        .and_then(|it| {
17858                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17859                        })
17860                        .is_some_and(|it| *it == key)
17861                })
17862        });
17863        let was_existing = existing.is_some();
17864        let editor = existing.unwrap_or_else(|| {
17865            cx.new(|cx| {
17866                let mut editor = Editor::for_multibuffer(
17867                    excerpt_buffer,
17868                    Some(workspace.project().clone()),
17869                    window,
17870                    cx,
17871                );
17872                editor.lookup_key = Some(Box::new(key));
17873                editor
17874            })
17875        });
17876        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17877            MultibufferSelectionMode::First => {
17878                if let Some(first_range) = ranges.first() {
17879                    editor.change_selections(
17880                        SelectionEffects::no_scroll(),
17881                        window,
17882                        cx,
17883                        |selections| {
17884                            selections.clear_disjoint();
17885                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17886                        },
17887                    );
17888                }
17889                editor.highlight_background::<Self>(
17890                    &ranges,
17891                    |_, theme| theme.colors().editor_highlighted_line_background,
17892                    cx,
17893                );
17894            }
17895            MultibufferSelectionMode::All => {
17896                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17897                    selections.clear_disjoint();
17898                    selections.select_anchor_ranges(ranges);
17899                });
17900            }
17901        });
17902
17903        let item = Box::new(editor);
17904
17905        let pane = if split {
17906            workspace.adjacent_pane(window, cx)
17907        } else {
17908            workspace.active_pane().clone()
17909        };
17910        let activate_pane = split;
17911
17912        let mut destination_index = None;
17913        pane.update(cx, |pane, cx| {
17914            if allow_preview && !was_existing {
17915                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
17916            }
17917            if was_existing && !allow_preview {
17918                pane.unpreview_item_if_preview(item.item_id());
17919            }
17920            pane.add_item(item, activate_pane, true, destination_index, window, cx);
17921        });
17922    }
17923
17924    pub fn rename(
17925        &mut self,
17926        _: &Rename,
17927        window: &mut Window,
17928        cx: &mut Context<Self>,
17929    ) -> Option<Task<Result<()>>> {
17930        use language::ToOffset as _;
17931
17932        let provider = self.semantics_provider.clone()?;
17933        let selection = self.selections.newest_anchor().clone();
17934        let (cursor_buffer, cursor_buffer_position) = self
17935            .buffer
17936            .read(cx)
17937            .text_anchor_for_position(selection.head(), cx)?;
17938        let (tail_buffer, cursor_buffer_position_end) = self
17939            .buffer
17940            .read(cx)
17941            .text_anchor_for_position(selection.tail(), cx)?;
17942        if tail_buffer != cursor_buffer {
17943            return None;
17944        }
17945
17946        let snapshot = cursor_buffer.read(cx).snapshot();
17947        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17948        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17949        let prepare_rename = provider
17950            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17951            .unwrap_or_else(|| Task::ready(Ok(None)));
17952        drop(snapshot);
17953
17954        Some(cx.spawn_in(window, async move |this, cx| {
17955            let rename_range = if let Some(range) = prepare_rename.await? {
17956                Some(range)
17957            } else {
17958                this.update(cx, |this, cx| {
17959                    let buffer = this.buffer.read(cx).snapshot(cx);
17960                    let mut buffer_highlights = this
17961                        .document_highlights_for_position(selection.head(), &buffer)
17962                        .filter(|highlight| {
17963                            highlight.start.excerpt_id == selection.head().excerpt_id
17964                                && highlight.end.excerpt_id == selection.head().excerpt_id
17965                        });
17966                    buffer_highlights
17967                        .next()
17968                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17969                })?
17970            };
17971            if let Some(rename_range) = rename_range {
17972                this.update_in(cx, |this, window, cx| {
17973                    let snapshot = cursor_buffer.read(cx).snapshot();
17974                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17975                    let cursor_offset_in_rename_range =
17976                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17977                    let cursor_offset_in_rename_range_end =
17978                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17979
17980                    this.take_rename(false, window, cx);
17981                    let buffer = this.buffer.read(cx).read(cx);
17982                    let cursor_offset = selection.head().to_offset(&buffer);
17983                    let rename_start =
17984                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17985                    let rename_end = rename_start + rename_buffer_range.len();
17986                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17987                    let mut old_highlight_id = None;
17988                    let old_name: Arc<str> = buffer
17989                        .chunks(rename_start..rename_end, true)
17990                        .map(|chunk| {
17991                            if old_highlight_id.is_none() {
17992                                old_highlight_id = chunk.syntax_highlight_id;
17993                            }
17994                            chunk.text
17995                        })
17996                        .collect::<String>()
17997                        .into();
17998
17999                    drop(buffer);
18000
18001                    // Position the selection in the rename editor so that it matches the current selection.
18002                    this.show_local_selections = false;
18003                    let rename_editor = cx.new(|cx| {
18004                        let mut editor = Editor::single_line(window, cx);
18005                        editor.buffer.update(cx, |buffer, cx| {
18006                            buffer.edit(
18007                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18008                                None,
18009                                cx,
18010                            )
18011                        });
18012                        let cursor_offset_in_rename_range =
18013                            MultiBufferOffset(cursor_offset_in_rename_range);
18014                        let cursor_offset_in_rename_range_end =
18015                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18016                        let rename_selection_range = match cursor_offset_in_rename_range
18017                            .cmp(&cursor_offset_in_rename_range_end)
18018                        {
18019                            Ordering::Equal => {
18020                                editor.select_all(&SelectAll, window, cx);
18021                                return editor;
18022                            }
18023                            Ordering::Less => {
18024                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18025                            }
18026                            Ordering::Greater => {
18027                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18028                            }
18029                        };
18030                        if rename_selection_range.end.0 > old_name.len() {
18031                            editor.select_all(&SelectAll, window, cx);
18032                        } else {
18033                            editor.change_selections(Default::default(), window, cx, |s| {
18034                                s.select_ranges([rename_selection_range]);
18035                            });
18036                        }
18037                        editor
18038                    });
18039                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18040                        if e == &EditorEvent::Focused {
18041                            cx.emit(EditorEvent::FocusedIn)
18042                        }
18043                    })
18044                    .detach();
18045
18046                    let write_highlights =
18047                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18048                    let read_highlights =
18049                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18050                    let ranges = write_highlights
18051                        .iter()
18052                        .flat_map(|(_, ranges)| ranges.iter())
18053                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18054                        .cloned()
18055                        .collect();
18056
18057                    this.highlight_text::<Rename>(
18058                        ranges,
18059                        HighlightStyle {
18060                            fade_out: Some(0.6),
18061                            ..Default::default()
18062                        },
18063                        cx,
18064                    );
18065                    let rename_focus_handle = rename_editor.focus_handle(cx);
18066                    window.focus(&rename_focus_handle);
18067                    let block_id = this.insert_blocks(
18068                        [BlockProperties {
18069                            style: BlockStyle::Flex,
18070                            placement: BlockPlacement::Below(range.start),
18071                            height: Some(1),
18072                            render: Arc::new({
18073                                let rename_editor = rename_editor.clone();
18074                                move |cx: &mut BlockContext| {
18075                                    let mut text_style = cx.editor_style.text.clone();
18076                                    if let Some(highlight_style) = old_highlight_id
18077                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18078                                    {
18079                                        text_style = text_style.highlight(highlight_style);
18080                                    }
18081                                    div()
18082                                        .block_mouse_except_scroll()
18083                                        .pl(cx.anchor_x)
18084                                        .child(EditorElement::new(
18085                                            &rename_editor,
18086                                            EditorStyle {
18087                                                background: cx.theme().system().transparent,
18088                                                local_player: cx.editor_style.local_player,
18089                                                text: text_style,
18090                                                scrollbar_width: cx.editor_style.scrollbar_width,
18091                                                syntax: cx.editor_style.syntax.clone(),
18092                                                status: cx.editor_style.status.clone(),
18093                                                inlay_hints_style: HighlightStyle {
18094                                                    font_weight: Some(FontWeight::BOLD),
18095                                                    ..make_inlay_hints_style(cx.app)
18096                                                },
18097                                                edit_prediction_styles: make_suggestion_styles(
18098                                                    cx.app,
18099                                                ),
18100                                                ..EditorStyle::default()
18101                                            },
18102                                        ))
18103                                        .into_any_element()
18104                                }
18105                            }),
18106                            priority: 0,
18107                        }],
18108                        Some(Autoscroll::fit()),
18109                        cx,
18110                    )[0];
18111                    this.pending_rename = Some(RenameState {
18112                        range,
18113                        old_name,
18114                        editor: rename_editor,
18115                        block_id,
18116                    });
18117                })?;
18118            }
18119
18120            Ok(())
18121        }))
18122    }
18123
18124    pub fn confirm_rename(
18125        &mut self,
18126        _: &ConfirmRename,
18127        window: &mut Window,
18128        cx: &mut Context<Self>,
18129    ) -> Option<Task<Result<()>>> {
18130        let rename = self.take_rename(false, window, cx)?;
18131        let workspace = self.workspace()?.downgrade();
18132        let (buffer, start) = self
18133            .buffer
18134            .read(cx)
18135            .text_anchor_for_position(rename.range.start, cx)?;
18136        let (end_buffer, _) = self
18137            .buffer
18138            .read(cx)
18139            .text_anchor_for_position(rename.range.end, cx)?;
18140        if buffer != end_buffer {
18141            return None;
18142        }
18143
18144        let old_name = rename.old_name;
18145        let new_name = rename.editor.read(cx).text(cx);
18146
18147        let rename = self.semantics_provider.as_ref()?.perform_rename(
18148            &buffer,
18149            start,
18150            new_name.clone(),
18151            cx,
18152        )?;
18153
18154        Some(cx.spawn_in(window, async move |editor, cx| {
18155            let project_transaction = rename.await?;
18156            Self::open_project_transaction(
18157                &editor,
18158                workspace,
18159                project_transaction,
18160                format!("Rename: {}{}", old_name, new_name),
18161                cx,
18162            )
18163            .await?;
18164
18165            editor.update(cx, |editor, cx| {
18166                editor.refresh_document_highlights(cx);
18167            })?;
18168            Ok(())
18169        }))
18170    }
18171
18172    fn take_rename(
18173        &mut self,
18174        moving_cursor: bool,
18175        window: &mut Window,
18176        cx: &mut Context<Self>,
18177    ) -> Option<RenameState> {
18178        let rename = self.pending_rename.take()?;
18179        if rename.editor.focus_handle(cx).is_focused(window) {
18180            window.focus(&self.focus_handle);
18181        }
18182
18183        self.remove_blocks(
18184            [rename.block_id].into_iter().collect(),
18185            Some(Autoscroll::fit()),
18186            cx,
18187        );
18188        self.clear_highlights::<Rename>(cx);
18189        self.show_local_selections = true;
18190
18191        if moving_cursor {
18192            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18193                editor
18194                    .selections
18195                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18196                    .head()
18197            });
18198
18199            // Update the selection to match the position of the selection inside
18200            // the rename editor.
18201            let snapshot = self.buffer.read(cx).read(cx);
18202            let rename_range = rename.range.to_offset(&snapshot);
18203            let cursor_in_editor = snapshot
18204                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18205                .min(rename_range.end);
18206            drop(snapshot);
18207
18208            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18209                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18210            });
18211        } else {
18212            self.refresh_document_highlights(cx);
18213        }
18214
18215        Some(rename)
18216    }
18217
18218    pub fn pending_rename(&self) -> Option<&RenameState> {
18219        self.pending_rename.as_ref()
18220    }
18221
18222    fn format(
18223        &mut self,
18224        _: &Format,
18225        window: &mut Window,
18226        cx: &mut Context<Self>,
18227    ) -> Option<Task<Result<()>>> {
18228        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18229
18230        let project = match &self.project {
18231            Some(project) => project.clone(),
18232            None => return None,
18233        };
18234
18235        Some(self.perform_format(
18236            project,
18237            FormatTrigger::Manual,
18238            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18239            window,
18240            cx,
18241        ))
18242    }
18243
18244    fn format_selections(
18245        &mut self,
18246        _: &FormatSelections,
18247        window: &mut Window,
18248        cx: &mut Context<Self>,
18249    ) -> Option<Task<Result<()>>> {
18250        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18251
18252        let project = match &self.project {
18253            Some(project) => project.clone(),
18254            None => return None,
18255        };
18256
18257        let ranges = self
18258            .selections
18259            .all_adjusted(&self.display_snapshot(cx))
18260            .into_iter()
18261            .map(|selection| selection.range())
18262            .collect_vec();
18263
18264        Some(self.perform_format(
18265            project,
18266            FormatTrigger::Manual,
18267            FormatTarget::Ranges(ranges),
18268            window,
18269            cx,
18270        ))
18271    }
18272
18273    fn perform_format(
18274        &mut self,
18275        project: Entity<Project>,
18276        trigger: FormatTrigger,
18277        target: FormatTarget,
18278        window: &mut Window,
18279        cx: &mut Context<Self>,
18280    ) -> Task<Result<()>> {
18281        let buffer = self.buffer.clone();
18282        let (buffers, target) = match target {
18283            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18284            FormatTarget::Ranges(selection_ranges) => {
18285                let multi_buffer = buffer.read(cx);
18286                let snapshot = multi_buffer.read(cx);
18287                let mut buffers = HashSet::default();
18288                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18289                    BTreeMap::new();
18290                for selection_range in selection_ranges {
18291                    for (buffer, buffer_range, _) in
18292                        snapshot.range_to_buffer_ranges(selection_range)
18293                    {
18294                        let buffer_id = buffer.remote_id();
18295                        let start = buffer.anchor_before(buffer_range.start);
18296                        let end = buffer.anchor_after(buffer_range.end);
18297                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18298                        buffer_id_to_ranges
18299                            .entry(buffer_id)
18300                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18301                            .or_insert_with(|| vec![start..end]);
18302                    }
18303                }
18304                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18305            }
18306        };
18307
18308        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18309        let selections_prev = transaction_id_prev
18310            .and_then(|transaction_id_prev| {
18311                // default to selections as they were after the last edit, if we have them,
18312                // instead of how they are now.
18313                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18314                // will take you back to where you made the last edit, instead of staying where you scrolled
18315                self.selection_history
18316                    .transaction(transaction_id_prev)
18317                    .map(|t| t.0.clone())
18318            })
18319            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18320
18321        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18322        let format = project.update(cx, |project, cx| {
18323            project.format(buffers, target, true, trigger, cx)
18324        });
18325
18326        cx.spawn_in(window, async move |editor, cx| {
18327            let transaction = futures::select_biased! {
18328                transaction = format.log_err().fuse() => transaction,
18329                () = timeout => {
18330                    log::warn!("timed out waiting for formatting");
18331                    None
18332                }
18333            };
18334
18335            buffer
18336                .update(cx, |buffer, cx| {
18337                    if let Some(transaction) = transaction
18338                        && !buffer.is_singleton()
18339                    {
18340                        buffer.push_transaction(&transaction.0, cx);
18341                    }
18342                    cx.notify();
18343                })
18344                .ok();
18345
18346            if let Some(transaction_id_now) =
18347                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18348            {
18349                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18350                if has_new_transaction {
18351                    _ = editor.update(cx, |editor, _| {
18352                        editor
18353                            .selection_history
18354                            .insert_transaction(transaction_id_now, selections_prev);
18355                    });
18356                }
18357            }
18358
18359            Ok(())
18360        })
18361    }
18362
18363    fn organize_imports(
18364        &mut self,
18365        _: &OrganizeImports,
18366        window: &mut Window,
18367        cx: &mut Context<Self>,
18368    ) -> Option<Task<Result<()>>> {
18369        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18370        let project = match &self.project {
18371            Some(project) => project.clone(),
18372            None => return None,
18373        };
18374        Some(self.perform_code_action_kind(
18375            project,
18376            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18377            window,
18378            cx,
18379        ))
18380    }
18381
18382    fn perform_code_action_kind(
18383        &mut self,
18384        project: Entity<Project>,
18385        kind: CodeActionKind,
18386        window: &mut Window,
18387        cx: &mut Context<Self>,
18388    ) -> Task<Result<()>> {
18389        let buffer = self.buffer.clone();
18390        let buffers = buffer.read(cx).all_buffers();
18391        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18392        let apply_action = project.update(cx, |project, cx| {
18393            project.apply_code_action_kind(buffers, kind, true, cx)
18394        });
18395        cx.spawn_in(window, async move |_, cx| {
18396            let transaction = futures::select_biased! {
18397                () = timeout => {
18398                    log::warn!("timed out waiting for executing code action");
18399                    None
18400                }
18401                transaction = apply_action.log_err().fuse() => transaction,
18402            };
18403            buffer
18404                .update(cx, |buffer, cx| {
18405                    // check if we need this
18406                    if let Some(transaction) = transaction
18407                        && !buffer.is_singleton()
18408                    {
18409                        buffer.push_transaction(&transaction.0, cx);
18410                    }
18411                    cx.notify();
18412                })
18413                .ok();
18414            Ok(())
18415        })
18416    }
18417
18418    pub fn restart_language_server(
18419        &mut self,
18420        _: &RestartLanguageServer,
18421        _: &mut Window,
18422        cx: &mut Context<Self>,
18423    ) {
18424        if let Some(project) = self.project.clone() {
18425            self.buffer.update(cx, |multi_buffer, cx| {
18426                project.update(cx, |project, cx| {
18427                    project.restart_language_servers_for_buffers(
18428                        multi_buffer.all_buffers().into_iter().collect(),
18429                        HashSet::default(),
18430                        cx,
18431                    );
18432                });
18433            })
18434        }
18435    }
18436
18437    pub fn stop_language_server(
18438        &mut self,
18439        _: &StopLanguageServer,
18440        _: &mut Window,
18441        cx: &mut Context<Self>,
18442    ) {
18443        if let Some(project) = self.project.clone() {
18444            self.buffer.update(cx, |multi_buffer, cx| {
18445                project.update(cx, |project, cx| {
18446                    project.stop_language_servers_for_buffers(
18447                        multi_buffer.all_buffers().into_iter().collect(),
18448                        HashSet::default(),
18449                        cx,
18450                    );
18451                });
18452            });
18453            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18454        }
18455    }
18456
18457    fn cancel_language_server_work(
18458        workspace: &mut Workspace,
18459        _: &actions::CancelLanguageServerWork,
18460        _: &mut Window,
18461        cx: &mut Context<Workspace>,
18462    ) {
18463        let project = workspace.project();
18464        let buffers = workspace
18465            .active_item(cx)
18466            .and_then(|item| item.act_as::<Editor>(cx))
18467            .map_or(HashSet::default(), |editor| {
18468                editor.read(cx).buffer.read(cx).all_buffers()
18469            });
18470        project.update(cx, |project, cx| {
18471            project.cancel_language_server_work_for_buffers(buffers, cx);
18472        });
18473    }
18474
18475    fn show_character_palette(
18476        &mut self,
18477        _: &ShowCharacterPalette,
18478        window: &mut Window,
18479        _: &mut Context<Self>,
18480    ) {
18481        window.show_character_palette();
18482    }
18483
18484    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18485        if !self.diagnostics_enabled() {
18486            return;
18487        }
18488
18489        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18490            let buffer = self.buffer.read(cx).snapshot(cx);
18491            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18492            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18493            let is_valid = buffer
18494                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18495                .any(|entry| {
18496                    entry.diagnostic.is_primary
18497                        && !entry.range.is_empty()
18498                        && entry.range.start == primary_range_start
18499                        && entry.diagnostic.message == active_diagnostics.active_message
18500                });
18501
18502            if !is_valid {
18503                self.dismiss_diagnostics(cx);
18504            }
18505        }
18506    }
18507
18508    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18509        match &self.active_diagnostics {
18510            ActiveDiagnostic::Group(group) => Some(group),
18511            _ => None,
18512        }
18513    }
18514
18515    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18516        if !self.diagnostics_enabled() {
18517            return;
18518        }
18519        self.dismiss_diagnostics(cx);
18520        self.active_diagnostics = ActiveDiagnostic::All;
18521    }
18522
18523    fn activate_diagnostics(
18524        &mut self,
18525        buffer_id: BufferId,
18526        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18527        window: &mut Window,
18528        cx: &mut Context<Self>,
18529    ) {
18530        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18531            return;
18532        }
18533        self.dismiss_diagnostics(cx);
18534        let snapshot = self.snapshot(window, cx);
18535        let buffer = self.buffer.read(cx).snapshot(cx);
18536        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18537            return;
18538        };
18539
18540        let diagnostic_group = buffer
18541            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18542            .collect::<Vec<_>>();
18543
18544        let language_registry = self
18545            .project()
18546            .map(|project| project.read(cx).languages().clone());
18547
18548        let blocks = renderer.render_group(
18549            diagnostic_group,
18550            buffer_id,
18551            snapshot,
18552            cx.weak_entity(),
18553            language_registry,
18554            cx,
18555        );
18556
18557        let blocks = self.display_map.update(cx, |display_map, cx| {
18558            display_map.insert_blocks(blocks, cx).into_iter().collect()
18559        });
18560        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18561            active_range: buffer.anchor_before(diagnostic.range.start)
18562                ..buffer.anchor_after(diagnostic.range.end),
18563            active_message: diagnostic.diagnostic.message.clone(),
18564            group_id: diagnostic.diagnostic.group_id,
18565            blocks,
18566        });
18567        cx.notify();
18568    }
18569
18570    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18571        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18572            return;
18573        };
18574
18575        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18576        if let ActiveDiagnostic::Group(group) = prev {
18577            self.display_map.update(cx, |display_map, cx| {
18578                display_map.remove_blocks(group.blocks, cx);
18579            });
18580            cx.notify();
18581        }
18582    }
18583
18584    /// Disable inline diagnostics rendering for this editor.
18585    pub fn disable_inline_diagnostics(&mut self) {
18586        self.inline_diagnostics_enabled = false;
18587        self.inline_diagnostics_update = Task::ready(());
18588        self.inline_diagnostics.clear();
18589    }
18590
18591    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18592        self.diagnostics_enabled = false;
18593        self.dismiss_diagnostics(cx);
18594        self.inline_diagnostics_update = Task::ready(());
18595        self.inline_diagnostics.clear();
18596    }
18597
18598    pub fn disable_word_completions(&mut self) {
18599        self.word_completions_enabled = false;
18600    }
18601
18602    pub fn diagnostics_enabled(&self) -> bool {
18603        self.diagnostics_enabled && self.mode.is_full()
18604    }
18605
18606    pub fn inline_diagnostics_enabled(&self) -> bool {
18607        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18608    }
18609
18610    pub fn show_inline_diagnostics(&self) -> bool {
18611        self.show_inline_diagnostics
18612    }
18613
18614    pub fn toggle_inline_diagnostics(
18615        &mut self,
18616        _: &ToggleInlineDiagnostics,
18617        window: &mut Window,
18618        cx: &mut Context<Editor>,
18619    ) {
18620        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18621        self.refresh_inline_diagnostics(false, window, cx);
18622    }
18623
18624    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18625        self.diagnostics_max_severity = severity;
18626        self.display_map.update(cx, |display_map, _| {
18627            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18628        });
18629    }
18630
18631    pub fn toggle_diagnostics(
18632        &mut self,
18633        _: &ToggleDiagnostics,
18634        window: &mut Window,
18635        cx: &mut Context<Editor>,
18636    ) {
18637        if !self.diagnostics_enabled() {
18638            return;
18639        }
18640
18641        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18642            EditorSettings::get_global(cx)
18643                .diagnostics_max_severity
18644                .filter(|severity| severity != &DiagnosticSeverity::Off)
18645                .unwrap_or(DiagnosticSeverity::Hint)
18646        } else {
18647            DiagnosticSeverity::Off
18648        };
18649        self.set_max_diagnostics_severity(new_severity, cx);
18650        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18651            self.active_diagnostics = ActiveDiagnostic::None;
18652            self.inline_diagnostics_update = Task::ready(());
18653            self.inline_diagnostics.clear();
18654        } else {
18655            self.refresh_inline_diagnostics(false, window, cx);
18656        }
18657
18658        cx.notify();
18659    }
18660
18661    pub fn toggle_minimap(
18662        &mut self,
18663        _: &ToggleMinimap,
18664        window: &mut Window,
18665        cx: &mut Context<Editor>,
18666    ) {
18667        if self.supports_minimap(cx) {
18668            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18669        }
18670    }
18671
18672    fn refresh_inline_diagnostics(
18673        &mut self,
18674        debounce: bool,
18675        window: &mut Window,
18676        cx: &mut Context<Self>,
18677    ) {
18678        let max_severity = ProjectSettings::get_global(cx)
18679            .diagnostics
18680            .inline
18681            .max_severity
18682            .unwrap_or(self.diagnostics_max_severity);
18683
18684        if !self.inline_diagnostics_enabled()
18685            || !self.diagnostics_enabled()
18686            || !self.show_inline_diagnostics
18687            || max_severity == DiagnosticSeverity::Off
18688        {
18689            self.inline_diagnostics_update = Task::ready(());
18690            self.inline_diagnostics.clear();
18691            return;
18692        }
18693
18694        let debounce_ms = ProjectSettings::get_global(cx)
18695            .diagnostics
18696            .inline
18697            .update_debounce_ms;
18698        let debounce = if debounce && debounce_ms > 0 {
18699            Some(Duration::from_millis(debounce_ms))
18700        } else {
18701            None
18702        };
18703        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18704            if let Some(debounce) = debounce {
18705                cx.background_executor().timer(debounce).await;
18706            }
18707            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18708                editor
18709                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18710                    .ok()
18711            }) else {
18712                return;
18713            };
18714
18715            let new_inline_diagnostics = cx
18716                .background_spawn(async move {
18717                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18718                    for diagnostic_entry in
18719                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18720                    {
18721                        let message = diagnostic_entry
18722                            .diagnostic
18723                            .message
18724                            .split_once('\n')
18725                            .map(|(line, _)| line)
18726                            .map(SharedString::new)
18727                            .unwrap_or_else(|| {
18728                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18729                            });
18730                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18731                        let (Ok(i) | Err(i)) = inline_diagnostics
18732                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18733                        inline_diagnostics.insert(
18734                            i,
18735                            (
18736                                start_anchor,
18737                                InlineDiagnostic {
18738                                    message,
18739                                    group_id: diagnostic_entry.diagnostic.group_id,
18740                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18741                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18742                                    severity: diagnostic_entry.diagnostic.severity,
18743                                },
18744                            ),
18745                        );
18746                    }
18747                    inline_diagnostics
18748                })
18749                .await;
18750
18751            editor
18752                .update(cx, |editor, cx| {
18753                    editor.inline_diagnostics = new_inline_diagnostics;
18754                    cx.notify();
18755                })
18756                .ok();
18757        });
18758    }
18759
18760    fn pull_diagnostics(
18761        &mut self,
18762        buffer_id: Option<BufferId>,
18763        window: &Window,
18764        cx: &mut Context<Self>,
18765    ) -> Option<()> {
18766        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18767            return None;
18768        }
18769        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18770            .diagnostics
18771            .lsp_pull_diagnostics;
18772        if !pull_diagnostics_settings.enabled {
18773            return None;
18774        }
18775        let project = self.project()?.downgrade();
18776
18777        let mut edited_buffer_ids = HashSet::default();
18778        let mut edited_worktree_ids = HashSet::default();
18779        let edited_buffers = match buffer_id {
18780            Some(buffer_id) => {
18781                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18782                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18783                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18784                edited_worktree_ids.insert(worktree_id);
18785                vec![buffer]
18786            }
18787            None => self
18788                .buffer()
18789                .read(cx)
18790                .all_buffers()
18791                .into_iter()
18792                .filter(|buffer| {
18793                    let buffer = buffer.read(cx);
18794                    match buffer.file().map(|f| f.worktree_id(cx)) {
18795                        Some(worktree_id) => {
18796                            edited_buffer_ids.insert(buffer.remote_id());
18797                            edited_worktree_ids.insert(worktree_id);
18798                            true
18799                        }
18800                        None => false,
18801                    }
18802                })
18803                .collect::<Vec<_>>(),
18804        };
18805
18806        if edited_buffers.is_empty() {
18807            self.pull_diagnostics_task = Task::ready(());
18808            self.pull_diagnostics_background_task = Task::ready(());
18809            return None;
18810        }
18811
18812        let mut already_used_buffers = HashSet::default();
18813        let related_open_buffers = self
18814            .workspace
18815            .as_ref()
18816            .and_then(|(workspace, _)| workspace.upgrade())
18817            .into_iter()
18818            .flat_map(|workspace| workspace.read(cx).panes())
18819            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18820            .filter(|editor| editor != &cx.entity())
18821            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18822            .filter(|buffer| {
18823                let buffer = buffer.read(cx);
18824                let buffer_id = buffer.remote_id();
18825                if already_used_buffers.insert(buffer_id) {
18826                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18827                        return !edited_buffer_ids.contains(&buffer_id)
18828                            && !edited_worktree_ids.contains(&worktree_id);
18829                    }
18830                }
18831                false
18832            })
18833            .collect::<Vec<_>>();
18834
18835        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18836        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18837            if buffers.is_empty() {
18838                return Task::ready(());
18839            }
18840            let project_weak = project.clone();
18841            cx.spawn_in(window, async move |_, cx| {
18842                cx.background_executor().timer(delay).await;
18843
18844                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18845                    buffers
18846                        .into_iter()
18847                        .filter_map(|buffer| {
18848                            project_weak
18849                                .update(cx, |project, cx| {
18850                                    project.lsp_store().update(cx, |lsp_store, cx| {
18851                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18852                                    })
18853                                })
18854                                .ok()
18855                        })
18856                        .collect::<FuturesUnordered<_>>()
18857                }) else {
18858                    return;
18859                };
18860
18861                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18862                    if let Err(e) = pull_task {
18863                        log::error!("Failed to update project diagnostics: {e:#}");
18864                    }
18865                }
18866            })
18867        };
18868
18869        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18870        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18871
18872        Some(())
18873    }
18874
18875    pub fn set_selections_from_remote(
18876        &mut self,
18877        selections: Vec<Selection<Anchor>>,
18878        pending_selection: Option<Selection<Anchor>>,
18879        window: &mut Window,
18880        cx: &mut Context<Self>,
18881    ) {
18882        let old_cursor_position = self.selections.newest_anchor().head();
18883        self.selections
18884            .change_with(&self.display_snapshot(cx), |s| {
18885                s.select_anchors(selections);
18886                if let Some(pending_selection) = pending_selection {
18887                    s.set_pending(pending_selection, SelectMode::Character);
18888                } else {
18889                    s.clear_pending();
18890                }
18891            });
18892        self.selections_did_change(
18893            false,
18894            &old_cursor_position,
18895            SelectionEffects::default(),
18896            window,
18897            cx,
18898        );
18899    }
18900
18901    pub fn transact(
18902        &mut self,
18903        window: &mut Window,
18904        cx: &mut Context<Self>,
18905        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18906    ) -> Option<TransactionId> {
18907        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18908            this.start_transaction_at(Instant::now(), window, cx);
18909            update(this, window, cx);
18910            this.end_transaction_at(Instant::now(), cx)
18911        })
18912    }
18913
18914    pub fn start_transaction_at(
18915        &mut self,
18916        now: Instant,
18917        window: &mut Window,
18918        cx: &mut Context<Self>,
18919    ) -> Option<TransactionId> {
18920        self.end_selection(window, cx);
18921        if let Some(tx_id) = self
18922            .buffer
18923            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18924        {
18925            self.selection_history
18926                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18927            cx.emit(EditorEvent::TransactionBegun {
18928                transaction_id: tx_id,
18929            });
18930            Some(tx_id)
18931        } else {
18932            None
18933        }
18934    }
18935
18936    pub fn end_transaction_at(
18937        &mut self,
18938        now: Instant,
18939        cx: &mut Context<Self>,
18940    ) -> Option<TransactionId> {
18941        if let Some(transaction_id) = self
18942            .buffer
18943            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18944        {
18945            if let Some((_, end_selections)) =
18946                self.selection_history.transaction_mut(transaction_id)
18947            {
18948                *end_selections = Some(self.selections.disjoint_anchors_arc());
18949            } else {
18950                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18951            }
18952
18953            cx.emit(EditorEvent::Edited { transaction_id });
18954            Some(transaction_id)
18955        } else {
18956            None
18957        }
18958    }
18959
18960    pub fn modify_transaction_selection_history(
18961        &mut self,
18962        transaction_id: TransactionId,
18963        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18964    ) -> bool {
18965        self.selection_history
18966            .transaction_mut(transaction_id)
18967            .map(modify)
18968            .is_some()
18969    }
18970
18971    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18972        if self.selection_mark_mode {
18973            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18974                s.move_with(|_, sel| {
18975                    sel.collapse_to(sel.head(), SelectionGoal::None);
18976                });
18977            })
18978        }
18979        self.selection_mark_mode = true;
18980        cx.notify();
18981    }
18982
18983    pub fn swap_selection_ends(
18984        &mut self,
18985        _: &actions::SwapSelectionEnds,
18986        window: &mut Window,
18987        cx: &mut Context<Self>,
18988    ) {
18989        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18990            s.move_with(|_, sel| {
18991                if sel.start != sel.end {
18992                    sel.reversed = !sel.reversed
18993                }
18994            });
18995        });
18996        self.request_autoscroll(Autoscroll::newest(), cx);
18997        cx.notify();
18998    }
18999
19000    pub fn toggle_focus(
19001        workspace: &mut Workspace,
19002        _: &actions::ToggleFocus,
19003        window: &mut Window,
19004        cx: &mut Context<Workspace>,
19005    ) {
19006        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19007            return;
19008        };
19009        workspace.activate_item(&item, true, true, window, cx);
19010    }
19011
19012    pub fn toggle_fold(
19013        &mut self,
19014        _: &actions::ToggleFold,
19015        window: &mut Window,
19016        cx: &mut Context<Self>,
19017    ) {
19018        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19019            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19020            let selection = self.selections.newest::<Point>(&display_map);
19021
19022            let range = if selection.is_empty() {
19023                let point = selection.head().to_display_point(&display_map);
19024                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19025                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19026                    .to_point(&display_map);
19027                start..end
19028            } else {
19029                selection.range()
19030            };
19031            if display_map.folds_in_range(range).next().is_some() {
19032                self.unfold_lines(&Default::default(), window, cx)
19033            } else {
19034                self.fold(&Default::default(), window, cx)
19035            }
19036        } else {
19037            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19038            let buffer_ids: HashSet<_> = self
19039                .selections
19040                .disjoint_anchor_ranges()
19041                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19042                .collect();
19043
19044            let should_unfold = buffer_ids
19045                .iter()
19046                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19047
19048            for buffer_id in buffer_ids {
19049                if should_unfold {
19050                    self.unfold_buffer(buffer_id, cx);
19051                } else {
19052                    self.fold_buffer(buffer_id, cx);
19053                }
19054            }
19055        }
19056    }
19057
19058    pub fn toggle_fold_recursive(
19059        &mut self,
19060        _: &actions::ToggleFoldRecursive,
19061        window: &mut Window,
19062        cx: &mut Context<Self>,
19063    ) {
19064        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19065
19066        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19067        let range = if selection.is_empty() {
19068            let point = selection.head().to_display_point(&display_map);
19069            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19070            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19071                .to_point(&display_map);
19072            start..end
19073        } else {
19074            selection.range()
19075        };
19076        if display_map.folds_in_range(range).next().is_some() {
19077            self.unfold_recursive(&Default::default(), window, cx)
19078        } else {
19079            self.fold_recursive(&Default::default(), window, cx)
19080        }
19081    }
19082
19083    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19084        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19085            let mut to_fold = Vec::new();
19086            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19087            let selections = self.selections.all_adjusted(&display_map);
19088
19089            for selection in selections {
19090                let range = selection.range().sorted();
19091                let buffer_start_row = range.start.row;
19092
19093                if range.start.row != range.end.row {
19094                    let mut found = false;
19095                    let mut row = range.start.row;
19096                    while row <= range.end.row {
19097                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19098                        {
19099                            found = true;
19100                            row = crease.range().end.row + 1;
19101                            to_fold.push(crease);
19102                        } else {
19103                            row += 1
19104                        }
19105                    }
19106                    if found {
19107                        continue;
19108                    }
19109                }
19110
19111                for row in (0..=range.start.row).rev() {
19112                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19113                        && crease.range().end.row >= buffer_start_row
19114                    {
19115                        to_fold.push(crease);
19116                        if row <= range.start.row {
19117                            break;
19118                        }
19119                    }
19120                }
19121            }
19122
19123            self.fold_creases(to_fold, true, window, cx);
19124        } else {
19125            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19126            let buffer_ids = self
19127                .selections
19128                .disjoint_anchor_ranges()
19129                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19130                .collect::<HashSet<_>>();
19131            for buffer_id in buffer_ids {
19132                self.fold_buffer(buffer_id, cx);
19133            }
19134        }
19135    }
19136
19137    pub fn toggle_fold_all(
19138        &mut self,
19139        _: &actions::ToggleFoldAll,
19140        window: &mut Window,
19141        cx: &mut Context<Self>,
19142    ) {
19143        if self.buffer.read(cx).is_singleton() {
19144            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19145            let has_folds = display_map
19146                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19147                .next()
19148                .is_some();
19149
19150            if has_folds {
19151                self.unfold_all(&actions::UnfoldAll, window, cx);
19152            } else {
19153                self.fold_all(&actions::FoldAll, window, cx);
19154            }
19155        } else {
19156            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19157            let should_unfold = buffer_ids
19158                .iter()
19159                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19160
19161            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19162                editor
19163                    .update_in(cx, |editor, _, cx| {
19164                        for buffer_id in buffer_ids {
19165                            if should_unfold {
19166                                editor.unfold_buffer(buffer_id, cx);
19167                            } else {
19168                                editor.fold_buffer(buffer_id, cx);
19169                            }
19170                        }
19171                    })
19172                    .ok();
19173            });
19174        }
19175    }
19176
19177    fn fold_at_level(
19178        &mut self,
19179        fold_at: &FoldAtLevel,
19180        window: &mut Window,
19181        cx: &mut Context<Self>,
19182    ) {
19183        if !self.buffer.read(cx).is_singleton() {
19184            return;
19185        }
19186
19187        let fold_at_level = fold_at.0;
19188        let snapshot = self.buffer.read(cx).snapshot(cx);
19189        let mut to_fold = Vec::new();
19190        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19191
19192        let row_ranges_to_keep: Vec<Range<u32>> = self
19193            .selections
19194            .all::<Point>(&self.display_snapshot(cx))
19195            .into_iter()
19196            .map(|sel| sel.start.row..sel.end.row)
19197            .collect();
19198
19199        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19200            while start_row < end_row {
19201                match self
19202                    .snapshot(window, cx)
19203                    .crease_for_buffer_row(MultiBufferRow(start_row))
19204                {
19205                    Some(crease) => {
19206                        let nested_start_row = crease.range().start.row + 1;
19207                        let nested_end_row = crease.range().end.row;
19208
19209                        if current_level < fold_at_level {
19210                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19211                        } else if current_level == fold_at_level {
19212                            // Fold iff there is no selection completely contained within the fold region
19213                            if !row_ranges_to_keep.iter().any(|selection| {
19214                                selection.end >= nested_start_row
19215                                    && selection.start <= nested_end_row
19216                            }) {
19217                                to_fold.push(crease);
19218                            }
19219                        }
19220
19221                        start_row = nested_end_row + 1;
19222                    }
19223                    None => start_row += 1,
19224                }
19225            }
19226        }
19227
19228        self.fold_creases(to_fold, true, window, cx);
19229    }
19230
19231    pub fn fold_at_level_1(
19232        &mut self,
19233        _: &actions::FoldAtLevel1,
19234        window: &mut Window,
19235        cx: &mut Context<Self>,
19236    ) {
19237        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19238    }
19239
19240    pub fn fold_at_level_2(
19241        &mut self,
19242        _: &actions::FoldAtLevel2,
19243        window: &mut Window,
19244        cx: &mut Context<Self>,
19245    ) {
19246        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19247    }
19248
19249    pub fn fold_at_level_3(
19250        &mut self,
19251        _: &actions::FoldAtLevel3,
19252        window: &mut Window,
19253        cx: &mut Context<Self>,
19254    ) {
19255        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19256    }
19257
19258    pub fn fold_at_level_4(
19259        &mut self,
19260        _: &actions::FoldAtLevel4,
19261        window: &mut Window,
19262        cx: &mut Context<Self>,
19263    ) {
19264        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19265    }
19266
19267    pub fn fold_at_level_5(
19268        &mut self,
19269        _: &actions::FoldAtLevel5,
19270        window: &mut Window,
19271        cx: &mut Context<Self>,
19272    ) {
19273        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19274    }
19275
19276    pub fn fold_at_level_6(
19277        &mut self,
19278        _: &actions::FoldAtLevel6,
19279        window: &mut Window,
19280        cx: &mut Context<Self>,
19281    ) {
19282        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19283    }
19284
19285    pub fn fold_at_level_7(
19286        &mut self,
19287        _: &actions::FoldAtLevel7,
19288        window: &mut Window,
19289        cx: &mut Context<Self>,
19290    ) {
19291        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19292    }
19293
19294    pub fn fold_at_level_8(
19295        &mut self,
19296        _: &actions::FoldAtLevel8,
19297        window: &mut Window,
19298        cx: &mut Context<Self>,
19299    ) {
19300        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19301    }
19302
19303    pub fn fold_at_level_9(
19304        &mut self,
19305        _: &actions::FoldAtLevel9,
19306        window: &mut Window,
19307        cx: &mut Context<Self>,
19308    ) {
19309        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19310    }
19311
19312    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19313        if self.buffer.read(cx).is_singleton() {
19314            let mut fold_ranges = Vec::new();
19315            let snapshot = self.buffer.read(cx).snapshot(cx);
19316
19317            for row in 0..snapshot.max_row().0 {
19318                if let Some(foldable_range) = self
19319                    .snapshot(window, cx)
19320                    .crease_for_buffer_row(MultiBufferRow(row))
19321                {
19322                    fold_ranges.push(foldable_range);
19323                }
19324            }
19325
19326            self.fold_creases(fold_ranges, true, window, cx);
19327        } else {
19328            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19329                editor
19330                    .update_in(cx, |editor, _, cx| {
19331                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19332                            editor.fold_buffer(buffer_id, cx);
19333                        }
19334                    })
19335                    .ok();
19336            });
19337        }
19338    }
19339
19340    pub fn fold_function_bodies(
19341        &mut self,
19342        _: &actions::FoldFunctionBodies,
19343        window: &mut Window,
19344        cx: &mut Context<Self>,
19345    ) {
19346        let snapshot = self.buffer.read(cx).snapshot(cx);
19347
19348        let ranges = snapshot
19349            .text_object_ranges(
19350                MultiBufferOffset(0)..snapshot.len(),
19351                TreeSitterOptions::default(),
19352            )
19353            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19354            .collect::<Vec<_>>();
19355
19356        let creases = ranges
19357            .into_iter()
19358            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19359            .collect();
19360
19361        self.fold_creases(creases, true, window, cx);
19362    }
19363
19364    pub fn fold_recursive(
19365        &mut self,
19366        _: &actions::FoldRecursive,
19367        window: &mut Window,
19368        cx: &mut Context<Self>,
19369    ) {
19370        let mut to_fold = Vec::new();
19371        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19372        let selections = self.selections.all_adjusted(&display_map);
19373
19374        for selection in selections {
19375            let range = selection.range().sorted();
19376            let buffer_start_row = range.start.row;
19377
19378            if range.start.row != range.end.row {
19379                let mut found = false;
19380                for row in range.start.row..=range.end.row {
19381                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19382                        found = true;
19383                        to_fold.push(crease);
19384                    }
19385                }
19386                if found {
19387                    continue;
19388                }
19389            }
19390
19391            for row in (0..=range.start.row).rev() {
19392                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19393                    if crease.range().end.row >= buffer_start_row {
19394                        to_fold.push(crease);
19395                    } else {
19396                        break;
19397                    }
19398                }
19399            }
19400        }
19401
19402        self.fold_creases(to_fold, true, window, cx);
19403    }
19404
19405    pub fn fold_at(
19406        &mut self,
19407        buffer_row: MultiBufferRow,
19408        window: &mut Window,
19409        cx: &mut Context<Self>,
19410    ) {
19411        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19412
19413        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19414            let autoscroll = self
19415                .selections
19416                .all::<Point>(&display_map)
19417                .iter()
19418                .any(|selection| crease.range().overlaps(&selection.range()));
19419
19420            self.fold_creases(vec![crease], autoscroll, window, cx);
19421        }
19422    }
19423
19424    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19425        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19426            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19427            let buffer = display_map.buffer_snapshot();
19428            let selections = self.selections.all::<Point>(&display_map);
19429            let ranges = selections
19430                .iter()
19431                .map(|s| {
19432                    let range = s.display_range(&display_map).sorted();
19433                    let mut start = range.start.to_point(&display_map);
19434                    let mut end = range.end.to_point(&display_map);
19435                    start.column = 0;
19436                    end.column = buffer.line_len(MultiBufferRow(end.row));
19437                    start..end
19438                })
19439                .collect::<Vec<_>>();
19440
19441            self.unfold_ranges(&ranges, true, true, cx);
19442        } else {
19443            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19444            let buffer_ids = self
19445                .selections
19446                .disjoint_anchor_ranges()
19447                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19448                .collect::<HashSet<_>>();
19449            for buffer_id in buffer_ids {
19450                self.unfold_buffer(buffer_id, cx);
19451            }
19452        }
19453    }
19454
19455    pub fn unfold_recursive(
19456        &mut self,
19457        _: &UnfoldRecursive,
19458        _window: &mut Window,
19459        cx: &mut Context<Self>,
19460    ) {
19461        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19462        let selections = self.selections.all::<Point>(&display_map);
19463        let ranges = selections
19464            .iter()
19465            .map(|s| {
19466                let mut range = s.display_range(&display_map).sorted();
19467                *range.start.column_mut() = 0;
19468                *range.end.column_mut() = display_map.line_len(range.end.row());
19469                let start = range.start.to_point(&display_map);
19470                let end = range.end.to_point(&display_map);
19471                start..end
19472            })
19473            .collect::<Vec<_>>();
19474
19475        self.unfold_ranges(&ranges, true, true, cx);
19476    }
19477
19478    pub fn unfold_at(
19479        &mut self,
19480        buffer_row: MultiBufferRow,
19481        _window: &mut Window,
19482        cx: &mut Context<Self>,
19483    ) {
19484        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19485
19486        let intersection_range = Point::new(buffer_row.0, 0)
19487            ..Point::new(
19488                buffer_row.0,
19489                display_map.buffer_snapshot().line_len(buffer_row),
19490            );
19491
19492        let autoscroll = self
19493            .selections
19494            .all::<Point>(&display_map)
19495            .iter()
19496            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19497
19498        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19499    }
19500
19501    pub fn unfold_all(
19502        &mut self,
19503        _: &actions::UnfoldAll,
19504        _window: &mut Window,
19505        cx: &mut Context<Self>,
19506    ) {
19507        if self.buffer.read(cx).is_singleton() {
19508            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19509            self.unfold_ranges(
19510                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19511                true,
19512                true,
19513                cx,
19514            );
19515        } else {
19516            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19517                editor
19518                    .update(cx, |editor, cx| {
19519                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19520                            editor.unfold_buffer(buffer_id, cx);
19521                        }
19522                    })
19523                    .ok();
19524            });
19525        }
19526    }
19527
19528    pub fn fold_selected_ranges(
19529        &mut self,
19530        _: &FoldSelectedRanges,
19531        window: &mut Window,
19532        cx: &mut Context<Self>,
19533    ) {
19534        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19535        let selections = self.selections.all_adjusted(&display_map);
19536        let ranges = selections
19537            .into_iter()
19538            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19539            .collect::<Vec<_>>();
19540        self.fold_creases(ranges, true, window, cx);
19541    }
19542
19543    pub fn fold_ranges<T: ToOffset + Clone>(
19544        &mut self,
19545        ranges: Vec<Range<T>>,
19546        auto_scroll: bool,
19547        window: &mut Window,
19548        cx: &mut Context<Self>,
19549    ) {
19550        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19551        let ranges = ranges
19552            .into_iter()
19553            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19554            .collect::<Vec<_>>();
19555        self.fold_creases(ranges, auto_scroll, window, cx);
19556    }
19557
19558    pub fn fold_creases<T: ToOffset + Clone>(
19559        &mut self,
19560        creases: Vec<Crease<T>>,
19561        auto_scroll: bool,
19562        _window: &mut Window,
19563        cx: &mut Context<Self>,
19564    ) {
19565        if creases.is_empty() {
19566            return;
19567        }
19568
19569        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19570
19571        if auto_scroll {
19572            self.request_autoscroll(Autoscroll::fit(), cx);
19573        }
19574
19575        cx.notify();
19576
19577        self.scrollbar_marker_state.dirty = true;
19578        self.folds_did_change(cx);
19579    }
19580
19581    /// Removes any folds whose ranges intersect any of the given ranges.
19582    pub fn unfold_ranges<T: ToOffset + Clone>(
19583        &mut self,
19584        ranges: &[Range<T>],
19585        inclusive: bool,
19586        auto_scroll: bool,
19587        cx: &mut Context<Self>,
19588    ) {
19589        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19590            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19591        });
19592        self.folds_did_change(cx);
19593    }
19594
19595    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19596        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19597            return;
19598        }
19599
19600        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19601        self.display_map.update(cx, |display_map, cx| {
19602            display_map.fold_buffers([buffer_id], cx)
19603        });
19604
19605        let snapshot = self.display_snapshot(cx);
19606        self.selections.change_with(&snapshot, |selections| {
19607            selections.remove_selections_from_buffer(buffer_id);
19608        });
19609
19610        cx.emit(EditorEvent::BufferFoldToggled {
19611            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19612            folded: true,
19613        });
19614        cx.notify();
19615    }
19616
19617    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19618        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19619            return;
19620        }
19621        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19622        self.display_map.update(cx, |display_map, cx| {
19623            display_map.unfold_buffers([buffer_id], cx);
19624        });
19625        cx.emit(EditorEvent::BufferFoldToggled {
19626            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19627            folded: false,
19628        });
19629        cx.notify();
19630    }
19631
19632    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19633        self.display_map.read(cx).is_buffer_folded(buffer)
19634    }
19635
19636    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19637        self.display_map.read(cx).folded_buffers()
19638    }
19639
19640    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19641        self.display_map.update(cx, |display_map, cx| {
19642            display_map.disable_header_for_buffer(buffer_id, cx);
19643        });
19644        cx.notify();
19645    }
19646
19647    /// Removes any folds with the given ranges.
19648    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19649        &mut self,
19650        ranges: &[Range<T>],
19651        type_id: TypeId,
19652        auto_scroll: bool,
19653        cx: &mut Context<Self>,
19654    ) {
19655        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19656            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19657        });
19658        self.folds_did_change(cx);
19659    }
19660
19661    fn remove_folds_with<T: ToOffset + Clone>(
19662        &mut self,
19663        ranges: &[Range<T>],
19664        auto_scroll: bool,
19665        cx: &mut Context<Self>,
19666        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19667    ) {
19668        if ranges.is_empty() {
19669            return;
19670        }
19671
19672        let mut buffers_affected = HashSet::default();
19673        let multi_buffer = self.buffer().read(cx);
19674        for range in ranges {
19675            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19676                buffers_affected.insert(buffer.read(cx).remote_id());
19677            };
19678        }
19679
19680        self.display_map.update(cx, update);
19681
19682        if auto_scroll {
19683            self.request_autoscroll(Autoscroll::fit(), cx);
19684        }
19685
19686        cx.notify();
19687        self.scrollbar_marker_state.dirty = true;
19688        self.active_indent_guides_state.dirty = true;
19689    }
19690
19691    pub fn update_renderer_widths(
19692        &mut self,
19693        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19694        cx: &mut Context<Self>,
19695    ) -> bool {
19696        self.display_map
19697            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19698    }
19699
19700    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19701        self.display_map.read(cx).fold_placeholder.clone()
19702    }
19703
19704    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19705        self.use_base_text_line_numbers = show;
19706    }
19707
19708    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19709        self.buffer.update(cx, |buffer, cx| {
19710            buffer.set_all_diff_hunks_expanded(cx);
19711        });
19712    }
19713
19714    pub fn expand_all_diff_hunks(
19715        &mut self,
19716        _: &ExpandAllDiffHunks,
19717        _window: &mut Window,
19718        cx: &mut Context<Self>,
19719    ) {
19720        self.buffer.update(cx, |buffer, cx| {
19721            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19722        });
19723    }
19724
19725    pub fn collapse_all_diff_hunks(
19726        &mut self,
19727        _: &CollapseAllDiffHunks,
19728        _window: &mut Window,
19729        cx: &mut Context<Self>,
19730    ) {
19731        self.buffer.update(cx, |buffer, cx| {
19732            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19733        });
19734    }
19735
19736    pub fn toggle_selected_diff_hunks(
19737        &mut self,
19738        _: &ToggleSelectedDiffHunks,
19739        _window: &mut Window,
19740        cx: &mut Context<Self>,
19741    ) {
19742        let ranges: Vec<_> = self
19743            .selections
19744            .disjoint_anchors()
19745            .iter()
19746            .map(|s| s.range())
19747            .collect();
19748        self.toggle_diff_hunks_in_ranges(ranges, cx);
19749    }
19750
19751    pub fn diff_hunks_in_ranges<'a>(
19752        &'a self,
19753        ranges: &'a [Range<Anchor>],
19754        buffer: &'a MultiBufferSnapshot,
19755    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19756        ranges.iter().flat_map(move |range| {
19757            let end_excerpt_id = range.end.excerpt_id;
19758            let range = range.to_point(buffer);
19759            let mut peek_end = range.end;
19760            if range.end.row < buffer.max_row().0 {
19761                peek_end = Point::new(range.end.row + 1, 0);
19762            }
19763            buffer
19764                .diff_hunks_in_range(range.start..peek_end)
19765                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19766        })
19767    }
19768
19769    pub fn has_stageable_diff_hunks_in_ranges(
19770        &self,
19771        ranges: &[Range<Anchor>],
19772        snapshot: &MultiBufferSnapshot,
19773    ) -> bool {
19774        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19775        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19776    }
19777
19778    pub fn toggle_staged_selected_diff_hunks(
19779        &mut self,
19780        _: &::git::ToggleStaged,
19781        _: &mut Window,
19782        cx: &mut Context<Self>,
19783    ) {
19784        let snapshot = self.buffer.read(cx).snapshot(cx);
19785        let ranges: Vec<_> = self
19786            .selections
19787            .disjoint_anchors()
19788            .iter()
19789            .map(|s| s.range())
19790            .collect();
19791        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19792        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19793    }
19794
19795    pub fn set_render_diff_hunk_controls(
19796        &mut self,
19797        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19798        cx: &mut Context<Self>,
19799    ) {
19800        self.render_diff_hunk_controls = render_diff_hunk_controls;
19801        cx.notify();
19802    }
19803
19804    pub fn stage_and_next(
19805        &mut self,
19806        _: &::git::StageAndNext,
19807        window: &mut Window,
19808        cx: &mut Context<Self>,
19809    ) {
19810        self.do_stage_or_unstage_and_next(true, window, cx);
19811    }
19812
19813    pub fn unstage_and_next(
19814        &mut self,
19815        _: &::git::UnstageAndNext,
19816        window: &mut Window,
19817        cx: &mut Context<Self>,
19818    ) {
19819        self.do_stage_or_unstage_and_next(false, window, cx);
19820    }
19821
19822    pub fn stage_or_unstage_diff_hunks(
19823        &mut self,
19824        stage: bool,
19825        ranges: Vec<Range<Anchor>>,
19826        cx: &mut Context<Self>,
19827    ) {
19828        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19829        cx.spawn(async move |this, cx| {
19830            task.await?;
19831            this.update(cx, |this, cx| {
19832                let snapshot = this.buffer.read(cx).snapshot(cx);
19833                let chunk_by = this
19834                    .diff_hunks_in_ranges(&ranges, &snapshot)
19835                    .chunk_by(|hunk| hunk.buffer_id);
19836                for (buffer_id, hunks) in &chunk_by {
19837                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19838                }
19839            })
19840        })
19841        .detach_and_log_err(cx);
19842    }
19843
19844    fn save_buffers_for_ranges_if_needed(
19845        &mut self,
19846        ranges: &[Range<Anchor>],
19847        cx: &mut Context<Editor>,
19848    ) -> Task<Result<()>> {
19849        let multibuffer = self.buffer.read(cx);
19850        let snapshot = multibuffer.read(cx);
19851        let buffer_ids: HashSet<_> = ranges
19852            .iter()
19853            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19854            .collect();
19855        drop(snapshot);
19856
19857        let mut buffers = HashSet::default();
19858        for buffer_id in buffer_ids {
19859            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19860                let buffer = buffer_entity.read(cx);
19861                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19862                {
19863                    buffers.insert(buffer_entity);
19864                }
19865            }
19866        }
19867
19868        if let Some(project) = &self.project {
19869            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19870        } else {
19871            Task::ready(Ok(()))
19872        }
19873    }
19874
19875    fn do_stage_or_unstage_and_next(
19876        &mut self,
19877        stage: bool,
19878        window: &mut Window,
19879        cx: &mut Context<Self>,
19880    ) {
19881        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19882
19883        if ranges.iter().any(|range| range.start != range.end) {
19884            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19885            return;
19886        }
19887
19888        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19889        let snapshot = self.snapshot(window, cx);
19890        let position = self
19891            .selections
19892            .newest::<Point>(&snapshot.display_snapshot)
19893            .head();
19894        let mut row = snapshot
19895            .buffer_snapshot()
19896            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19897            .find(|hunk| hunk.row_range.start.0 > position.row)
19898            .map(|hunk| hunk.row_range.start);
19899
19900        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19901        // Outside of the project diff editor, wrap around to the beginning.
19902        if !all_diff_hunks_expanded {
19903            row = row.or_else(|| {
19904                snapshot
19905                    .buffer_snapshot()
19906                    .diff_hunks_in_range(Point::zero()..position)
19907                    .find(|hunk| hunk.row_range.end.0 < position.row)
19908                    .map(|hunk| hunk.row_range.start)
19909            });
19910        }
19911
19912        if let Some(row) = row {
19913            let destination = Point::new(row.0, 0);
19914            let autoscroll = Autoscroll::center();
19915
19916            self.unfold_ranges(&[destination..destination], false, false, cx);
19917            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19918                s.select_ranges([destination..destination]);
19919            });
19920        }
19921    }
19922
19923    fn do_stage_or_unstage(
19924        &self,
19925        stage: bool,
19926        buffer_id: BufferId,
19927        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19928        cx: &mut App,
19929    ) -> Option<()> {
19930        let project = self.project()?;
19931        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19932        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19933        let buffer_snapshot = buffer.read(cx).snapshot();
19934        let file_exists = buffer_snapshot
19935            .file()
19936            .is_some_and(|file| file.disk_state().exists());
19937        diff.update(cx, |diff, cx| {
19938            diff.stage_or_unstage_hunks(
19939                stage,
19940                &hunks
19941                    .map(|hunk| buffer_diff::DiffHunk {
19942                        buffer_range: hunk.buffer_range,
19943                        // We don't need to pass in word diffs here because they're only used for rendering and
19944                        // this function changes internal state
19945                        base_word_diffs: Vec::default(),
19946                        buffer_word_diffs: Vec::default(),
19947                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19948                            ..hunk.diff_base_byte_range.end.0,
19949                        secondary_status: hunk.secondary_status,
19950                        range: Point::zero()..Point::zero(), // unused
19951                    })
19952                    .collect::<Vec<_>>(),
19953                &buffer_snapshot,
19954                file_exists,
19955                cx,
19956            )
19957        });
19958        None
19959    }
19960
19961    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19962        let ranges: Vec<_> = self
19963            .selections
19964            .disjoint_anchors()
19965            .iter()
19966            .map(|s| s.range())
19967            .collect();
19968        self.buffer
19969            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19970    }
19971
19972    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19973        self.buffer.update(cx, |buffer, cx| {
19974            let ranges = vec![Anchor::min()..Anchor::max()];
19975            if !buffer.all_diff_hunks_expanded()
19976                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19977            {
19978                buffer.collapse_diff_hunks(ranges, cx);
19979                true
19980            } else {
19981                false
19982            }
19983        })
19984    }
19985
19986    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19987        if self.buffer.read(cx).all_diff_hunks_expanded() {
19988            return true;
19989        }
19990        let ranges = vec![Anchor::min()..Anchor::max()];
19991        self.buffer
19992            .read(cx)
19993            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19994    }
19995
19996    fn toggle_diff_hunks_in_ranges(
19997        &mut self,
19998        ranges: Vec<Range<Anchor>>,
19999        cx: &mut Context<Editor>,
20000    ) {
20001        self.buffer.update(cx, |buffer, cx| {
20002            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20003            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20004        })
20005    }
20006
20007    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20008        self.buffer.update(cx, |buffer, cx| {
20009            let snapshot = buffer.snapshot(cx);
20010            let excerpt_id = range.end.excerpt_id;
20011            let point_range = range.to_point(&snapshot);
20012            let expand = !buffer.single_hunk_is_expanded(range, cx);
20013            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20014        })
20015    }
20016
20017    pub(crate) fn apply_all_diff_hunks(
20018        &mut self,
20019        _: &ApplyAllDiffHunks,
20020        window: &mut Window,
20021        cx: &mut Context<Self>,
20022    ) {
20023        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20024
20025        let buffers = self.buffer.read(cx).all_buffers();
20026        for branch_buffer in buffers {
20027            branch_buffer.update(cx, |branch_buffer, cx| {
20028                branch_buffer.merge_into_base(Vec::new(), cx);
20029            });
20030        }
20031
20032        if let Some(project) = self.project.clone() {
20033            self.save(
20034                SaveOptions {
20035                    format: true,
20036                    autosave: false,
20037                },
20038                project,
20039                window,
20040                cx,
20041            )
20042            .detach_and_log_err(cx);
20043        }
20044    }
20045
20046    pub(crate) fn apply_selected_diff_hunks(
20047        &mut self,
20048        _: &ApplyDiffHunk,
20049        window: &mut Window,
20050        cx: &mut Context<Self>,
20051    ) {
20052        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20053        let snapshot = self.snapshot(window, cx);
20054        let hunks = snapshot.hunks_for_ranges(
20055            self.selections
20056                .all(&snapshot.display_snapshot)
20057                .into_iter()
20058                .map(|selection| selection.range()),
20059        );
20060        let mut ranges_by_buffer = HashMap::default();
20061        self.transact(window, cx, |editor, _window, cx| {
20062            for hunk in hunks {
20063                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20064                    ranges_by_buffer
20065                        .entry(buffer.clone())
20066                        .or_insert_with(Vec::new)
20067                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20068                }
20069            }
20070
20071            for (buffer, ranges) in ranges_by_buffer {
20072                buffer.update(cx, |buffer, cx| {
20073                    buffer.merge_into_base(ranges, cx);
20074                });
20075            }
20076        });
20077
20078        if let Some(project) = self.project.clone() {
20079            self.save(
20080                SaveOptions {
20081                    format: true,
20082                    autosave: false,
20083                },
20084                project,
20085                window,
20086                cx,
20087            )
20088            .detach_and_log_err(cx);
20089        }
20090    }
20091
20092    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20093        if hovered != self.gutter_hovered {
20094            self.gutter_hovered = hovered;
20095            cx.notify();
20096        }
20097    }
20098
20099    pub fn insert_blocks(
20100        &mut self,
20101        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20102        autoscroll: Option<Autoscroll>,
20103        cx: &mut Context<Self>,
20104    ) -> Vec<CustomBlockId> {
20105        let blocks = self
20106            .display_map
20107            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20108        if let Some(autoscroll) = autoscroll {
20109            self.request_autoscroll(autoscroll, cx);
20110        }
20111        cx.notify();
20112        blocks
20113    }
20114
20115    pub fn resize_blocks(
20116        &mut self,
20117        heights: HashMap<CustomBlockId, u32>,
20118        autoscroll: Option<Autoscroll>,
20119        cx: &mut Context<Self>,
20120    ) {
20121        self.display_map
20122            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20123        if let Some(autoscroll) = autoscroll {
20124            self.request_autoscroll(autoscroll, cx);
20125        }
20126        cx.notify();
20127    }
20128
20129    pub fn replace_blocks(
20130        &mut self,
20131        renderers: HashMap<CustomBlockId, RenderBlock>,
20132        autoscroll: Option<Autoscroll>,
20133        cx: &mut Context<Self>,
20134    ) {
20135        self.display_map
20136            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20137        if let Some(autoscroll) = autoscroll {
20138            self.request_autoscroll(autoscroll, cx);
20139        }
20140        cx.notify();
20141    }
20142
20143    pub fn remove_blocks(
20144        &mut self,
20145        block_ids: HashSet<CustomBlockId>,
20146        autoscroll: Option<Autoscroll>,
20147        cx: &mut Context<Self>,
20148    ) {
20149        self.display_map.update(cx, |display_map, cx| {
20150            display_map.remove_blocks(block_ids, cx)
20151        });
20152        if let Some(autoscroll) = autoscroll {
20153            self.request_autoscroll(autoscroll, cx);
20154        }
20155        cx.notify();
20156    }
20157
20158    pub fn row_for_block(
20159        &self,
20160        block_id: CustomBlockId,
20161        cx: &mut Context<Self>,
20162    ) -> Option<DisplayRow> {
20163        self.display_map
20164            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20165    }
20166
20167    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20168        self.focused_block = Some(focused_block);
20169    }
20170
20171    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20172        self.focused_block.take()
20173    }
20174
20175    pub fn insert_creases(
20176        &mut self,
20177        creases: impl IntoIterator<Item = Crease<Anchor>>,
20178        cx: &mut Context<Self>,
20179    ) -> Vec<CreaseId> {
20180        self.display_map
20181            .update(cx, |map, cx| map.insert_creases(creases, cx))
20182    }
20183
20184    pub fn remove_creases(
20185        &mut self,
20186        ids: impl IntoIterator<Item = CreaseId>,
20187        cx: &mut Context<Self>,
20188    ) -> Vec<(CreaseId, Range<Anchor>)> {
20189        self.display_map
20190            .update(cx, |map, cx| map.remove_creases(ids, cx))
20191    }
20192
20193    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20194        self.display_map
20195            .update(cx, |map, cx| map.snapshot(cx))
20196            .longest_row()
20197    }
20198
20199    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20200        self.display_map
20201            .update(cx, |map, cx| map.snapshot(cx))
20202            .max_point()
20203    }
20204
20205    pub fn text(&self, cx: &App) -> String {
20206        self.buffer.read(cx).read(cx).text()
20207    }
20208
20209    pub fn is_empty(&self, cx: &App) -> bool {
20210        self.buffer.read(cx).read(cx).is_empty()
20211    }
20212
20213    pub fn text_option(&self, cx: &App) -> Option<String> {
20214        let text = self.text(cx);
20215        let text = text.trim();
20216
20217        if text.is_empty() {
20218            return None;
20219        }
20220
20221        Some(text.to_string())
20222    }
20223
20224    pub fn set_text(
20225        &mut self,
20226        text: impl Into<Arc<str>>,
20227        window: &mut Window,
20228        cx: &mut Context<Self>,
20229    ) {
20230        self.transact(window, cx, |this, _, cx| {
20231            this.buffer
20232                .read(cx)
20233                .as_singleton()
20234                .expect("you can only call set_text on editors for singleton buffers")
20235                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20236        });
20237    }
20238
20239    pub fn display_text(&self, cx: &mut App) -> String {
20240        self.display_map
20241            .update(cx, |map, cx| map.snapshot(cx))
20242            .text()
20243    }
20244
20245    fn create_minimap(
20246        &self,
20247        minimap_settings: MinimapSettings,
20248        window: &mut Window,
20249        cx: &mut Context<Self>,
20250    ) -> Option<Entity<Self>> {
20251        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20252            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20253    }
20254
20255    fn initialize_new_minimap(
20256        &self,
20257        minimap_settings: MinimapSettings,
20258        window: &mut Window,
20259        cx: &mut Context<Self>,
20260    ) -> Entity<Self> {
20261        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20262
20263        let mut minimap = Editor::new_internal(
20264            EditorMode::Minimap {
20265                parent: cx.weak_entity(),
20266            },
20267            self.buffer.clone(),
20268            None,
20269            Some(self.display_map.clone()),
20270            window,
20271            cx,
20272        );
20273        minimap.scroll_manager.clone_state(&self.scroll_manager);
20274        minimap.set_text_style_refinement(TextStyleRefinement {
20275            font_size: Some(MINIMAP_FONT_SIZE),
20276            font_weight: Some(MINIMAP_FONT_WEIGHT),
20277            ..Default::default()
20278        });
20279        minimap.update_minimap_configuration(minimap_settings, cx);
20280        cx.new(|_| minimap)
20281    }
20282
20283    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20284        let current_line_highlight = minimap_settings
20285            .current_line_highlight
20286            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20287        self.set_current_line_highlight(Some(current_line_highlight));
20288    }
20289
20290    pub fn minimap(&self) -> Option<&Entity<Self>> {
20291        self.minimap
20292            .as_ref()
20293            .filter(|_| self.minimap_visibility.visible())
20294    }
20295
20296    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20297        let mut wrap_guides = smallvec![];
20298
20299        if self.show_wrap_guides == Some(false) {
20300            return wrap_guides;
20301        }
20302
20303        let settings = self.buffer.read(cx).language_settings(cx);
20304        if settings.show_wrap_guides {
20305            match self.soft_wrap_mode(cx) {
20306                SoftWrap::Column(soft_wrap) => {
20307                    wrap_guides.push((soft_wrap as usize, true));
20308                }
20309                SoftWrap::Bounded(soft_wrap) => {
20310                    wrap_guides.push((soft_wrap as usize, true));
20311                }
20312                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20313            }
20314            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20315        }
20316
20317        wrap_guides
20318    }
20319
20320    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20321        let settings = self.buffer.read(cx).language_settings(cx);
20322        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20323        match mode {
20324            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20325                SoftWrap::None
20326            }
20327            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20328            language_settings::SoftWrap::PreferredLineLength => {
20329                SoftWrap::Column(settings.preferred_line_length)
20330            }
20331            language_settings::SoftWrap::Bounded => {
20332                SoftWrap::Bounded(settings.preferred_line_length)
20333            }
20334        }
20335    }
20336
20337    pub fn set_soft_wrap_mode(
20338        &mut self,
20339        mode: language_settings::SoftWrap,
20340
20341        cx: &mut Context<Self>,
20342    ) {
20343        self.soft_wrap_mode_override = Some(mode);
20344        cx.notify();
20345    }
20346
20347    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20348        self.hard_wrap = hard_wrap;
20349        cx.notify();
20350    }
20351
20352    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20353        self.text_style_refinement = Some(style);
20354    }
20355
20356    /// called by the Element so we know what style we were most recently rendered with.
20357    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20358        // We intentionally do not inform the display map about the minimap style
20359        // so that wrapping is not recalculated and stays consistent for the editor
20360        // and its linked minimap.
20361        if !self.mode.is_minimap() {
20362            let font = style.text.font();
20363            let font_size = style.text.font_size.to_pixels(window.rem_size());
20364            let display_map = self
20365                .placeholder_display_map
20366                .as_ref()
20367                .filter(|_| self.is_empty(cx))
20368                .unwrap_or(&self.display_map);
20369
20370            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20371        }
20372        self.style = Some(style);
20373    }
20374
20375    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20376        if self.style.is_none() {
20377            self.style = Some(self.create_style(cx));
20378        }
20379        self.style.as_ref().unwrap()
20380    }
20381
20382    // Called by the element. This method is not designed to be called outside of the editor
20383    // element's layout code because it does not notify when rewrapping is computed synchronously.
20384    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20385        if self.is_empty(cx) {
20386            self.placeholder_display_map
20387                .as_ref()
20388                .map_or(false, |display_map| {
20389                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20390                })
20391        } else {
20392            self.display_map
20393                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20394        }
20395    }
20396
20397    pub fn set_soft_wrap(&mut self) {
20398        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20399    }
20400
20401    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20402        if self.soft_wrap_mode_override.is_some() {
20403            self.soft_wrap_mode_override.take();
20404        } else {
20405            let soft_wrap = match self.soft_wrap_mode(cx) {
20406                SoftWrap::GitDiff => return,
20407                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20408                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20409                    language_settings::SoftWrap::None
20410                }
20411            };
20412            self.soft_wrap_mode_override = Some(soft_wrap);
20413        }
20414        cx.notify();
20415    }
20416
20417    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20418        let Some(workspace) = self.workspace() else {
20419            return;
20420        };
20421        let fs = workspace.read(cx).app_state().fs.clone();
20422        let current_show = TabBarSettings::get_global(cx).show;
20423        update_settings_file(fs, cx, move |setting, _| {
20424            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20425        });
20426    }
20427
20428    pub fn toggle_indent_guides(
20429        &mut self,
20430        _: &ToggleIndentGuides,
20431        _: &mut Window,
20432        cx: &mut Context<Self>,
20433    ) {
20434        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20435            self.buffer
20436                .read(cx)
20437                .language_settings(cx)
20438                .indent_guides
20439                .enabled
20440        });
20441        self.show_indent_guides = Some(!currently_enabled);
20442        cx.notify();
20443    }
20444
20445    fn should_show_indent_guides(&self) -> Option<bool> {
20446        self.show_indent_guides
20447    }
20448
20449    pub fn disable_indent_guides_for_buffer(
20450        &mut self,
20451        buffer_id: BufferId,
20452        cx: &mut Context<Self>,
20453    ) {
20454        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20455        cx.notify();
20456    }
20457
20458    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20459        self.buffers_with_disabled_indent_guides
20460            .contains(&buffer_id)
20461    }
20462
20463    pub fn toggle_line_numbers(
20464        &mut self,
20465        _: &ToggleLineNumbers,
20466        _: &mut Window,
20467        cx: &mut Context<Self>,
20468    ) {
20469        let mut editor_settings = EditorSettings::get_global(cx).clone();
20470        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20471        EditorSettings::override_global(editor_settings, cx);
20472    }
20473
20474    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20475        if let Some(show_line_numbers) = self.show_line_numbers {
20476            return show_line_numbers;
20477        }
20478        EditorSettings::get_global(cx).gutter.line_numbers
20479    }
20480
20481    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20482        match (
20483            self.use_relative_line_numbers,
20484            EditorSettings::get_global(cx).relative_line_numbers,
20485        ) {
20486            (None, setting) => setting,
20487            (Some(false), _) => RelativeLineNumbers::Disabled,
20488            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20489            (Some(true), _) => RelativeLineNumbers::Enabled,
20490        }
20491    }
20492
20493    pub fn toggle_relative_line_numbers(
20494        &mut self,
20495        _: &ToggleRelativeLineNumbers,
20496        _: &mut Window,
20497        cx: &mut Context<Self>,
20498    ) {
20499        let is_relative = self.relative_line_numbers(cx);
20500        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20501    }
20502
20503    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20504        self.use_relative_line_numbers = is_relative;
20505        cx.notify();
20506    }
20507
20508    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20509        self.show_gutter = show_gutter;
20510        cx.notify();
20511    }
20512
20513    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20514        self.show_scrollbars = ScrollbarAxes {
20515            horizontal: show,
20516            vertical: show,
20517        };
20518        cx.notify();
20519    }
20520
20521    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20522        self.show_scrollbars.vertical = show;
20523        cx.notify();
20524    }
20525
20526    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20527        self.show_scrollbars.horizontal = show;
20528        cx.notify();
20529    }
20530
20531    pub fn set_minimap_visibility(
20532        &mut self,
20533        minimap_visibility: MinimapVisibility,
20534        window: &mut Window,
20535        cx: &mut Context<Self>,
20536    ) {
20537        if self.minimap_visibility != minimap_visibility {
20538            if minimap_visibility.visible() && self.minimap.is_none() {
20539                let minimap_settings = EditorSettings::get_global(cx).minimap;
20540                self.minimap =
20541                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20542            }
20543            self.minimap_visibility = minimap_visibility;
20544            cx.notify();
20545        }
20546    }
20547
20548    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20549        self.set_show_scrollbars(false, cx);
20550        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20551    }
20552
20553    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20554        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20555    }
20556
20557    /// Normally the text in full mode and auto height editors is padded on the
20558    /// left side by roughly half a character width for improved hit testing.
20559    ///
20560    /// Use this method to disable this for cases where this is not wanted (e.g.
20561    /// if you want to align the editor text with some other text above or below)
20562    /// or if you want to add this padding to single-line editors.
20563    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20564        self.offset_content = offset_content;
20565        cx.notify();
20566    }
20567
20568    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20569        self.show_line_numbers = Some(show_line_numbers);
20570        cx.notify();
20571    }
20572
20573    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20574        self.disable_expand_excerpt_buttons = true;
20575        cx.notify();
20576    }
20577
20578    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20579        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20580        cx.notify();
20581    }
20582
20583    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20584        self.show_code_actions = Some(show_code_actions);
20585        cx.notify();
20586    }
20587
20588    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20589        self.show_runnables = Some(show_runnables);
20590        cx.notify();
20591    }
20592
20593    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20594        self.show_breakpoints = Some(show_breakpoints);
20595        cx.notify();
20596    }
20597
20598    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20599        if self.display_map.read(cx).masked != masked {
20600            self.display_map.update(cx, |map, _| map.masked = masked);
20601        }
20602        cx.notify()
20603    }
20604
20605    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20606        self.show_wrap_guides = Some(show_wrap_guides);
20607        cx.notify();
20608    }
20609
20610    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20611        self.show_indent_guides = Some(show_indent_guides);
20612        cx.notify();
20613    }
20614
20615    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20616        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20617            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20618                && let Some(dir) = file.abs_path(cx).parent()
20619            {
20620                return Some(dir.to_owned());
20621            }
20622        }
20623
20624        None
20625    }
20626
20627    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20628        self.active_excerpt(cx)?
20629            .1
20630            .read(cx)
20631            .file()
20632            .and_then(|f| f.as_local())
20633    }
20634
20635    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20636        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20637            let buffer = buffer.read(cx);
20638            if let Some(project_path) = buffer.project_path(cx) {
20639                let project = self.project()?.read(cx);
20640                project.absolute_path(&project_path, cx)
20641            } else {
20642                buffer
20643                    .file()
20644                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20645            }
20646        })
20647    }
20648
20649    pub fn reveal_in_finder(
20650        &mut self,
20651        _: &RevealInFileManager,
20652        _window: &mut Window,
20653        cx: &mut Context<Self>,
20654    ) {
20655        if let Some(target) = self.target_file(cx) {
20656            cx.reveal_path(&target.abs_path(cx));
20657        }
20658    }
20659
20660    pub fn copy_path(
20661        &mut self,
20662        _: &zed_actions::workspace::CopyPath,
20663        _window: &mut Window,
20664        cx: &mut Context<Self>,
20665    ) {
20666        if let Some(path) = self.target_file_abs_path(cx)
20667            && let Some(path) = path.to_str()
20668        {
20669            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20670        } else {
20671            cx.propagate();
20672        }
20673    }
20674
20675    pub fn copy_relative_path(
20676        &mut self,
20677        _: &zed_actions::workspace::CopyRelativePath,
20678        _window: &mut Window,
20679        cx: &mut Context<Self>,
20680    ) {
20681        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20682            let project = self.project()?.read(cx);
20683            let path = buffer.read(cx).file()?.path();
20684            let path = path.display(project.path_style(cx));
20685            Some(path)
20686        }) {
20687            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20688        } else {
20689            cx.propagate();
20690        }
20691    }
20692
20693    /// Returns the project path for the editor's buffer, if any buffer is
20694    /// opened in the editor.
20695    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20696        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20697            buffer.read(cx).project_path(cx)
20698        } else {
20699            None
20700        }
20701    }
20702
20703    // Returns true if the editor handled a go-to-line request
20704    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20705        maybe!({
20706            let breakpoint_store = self.breakpoint_store.as_ref()?;
20707
20708            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20709            else {
20710                self.clear_row_highlights::<ActiveDebugLine>();
20711                return None;
20712            };
20713
20714            let position = active_stack_frame.position;
20715            let buffer_id = position.buffer_id?;
20716            let snapshot = self
20717                .project
20718                .as_ref()?
20719                .read(cx)
20720                .buffer_for_id(buffer_id, cx)?
20721                .read(cx)
20722                .snapshot();
20723
20724            let mut handled = false;
20725            for (id, ExcerptRange { context, .. }) in
20726                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20727            {
20728                if context.start.cmp(&position, &snapshot).is_ge()
20729                    || context.end.cmp(&position, &snapshot).is_lt()
20730                {
20731                    continue;
20732                }
20733                let snapshot = self.buffer.read(cx).snapshot(cx);
20734                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20735
20736                handled = true;
20737                self.clear_row_highlights::<ActiveDebugLine>();
20738
20739                self.go_to_line::<ActiveDebugLine>(
20740                    multibuffer_anchor,
20741                    Some(cx.theme().colors().editor_debugger_active_line_background),
20742                    window,
20743                    cx,
20744                );
20745
20746                cx.notify();
20747            }
20748
20749            handled.then_some(())
20750        })
20751        .is_some()
20752    }
20753
20754    pub fn copy_file_name_without_extension(
20755        &mut self,
20756        _: &CopyFileNameWithoutExtension,
20757        _: &mut Window,
20758        cx: &mut Context<Self>,
20759    ) {
20760        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20761            let file = buffer.read(cx).file()?;
20762            file.path().file_stem()
20763        }) {
20764            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20765        }
20766    }
20767
20768    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20769        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20770            let file = buffer.read(cx).file()?;
20771            Some(file.file_name(cx))
20772        }) {
20773            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20774        }
20775    }
20776
20777    pub fn toggle_git_blame(
20778        &mut self,
20779        _: &::git::Blame,
20780        window: &mut Window,
20781        cx: &mut Context<Self>,
20782    ) {
20783        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20784
20785        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20786            self.start_git_blame(true, window, cx);
20787        }
20788
20789        cx.notify();
20790    }
20791
20792    pub fn toggle_git_blame_inline(
20793        &mut self,
20794        _: &ToggleGitBlameInline,
20795        window: &mut Window,
20796        cx: &mut Context<Self>,
20797    ) {
20798        self.toggle_git_blame_inline_internal(true, window, cx);
20799        cx.notify();
20800    }
20801
20802    pub fn open_git_blame_commit(
20803        &mut self,
20804        _: &OpenGitBlameCommit,
20805        window: &mut Window,
20806        cx: &mut Context<Self>,
20807    ) {
20808        self.open_git_blame_commit_internal(window, cx);
20809    }
20810
20811    fn open_git_blame_commit_internal(
20812        &mut self,
20813        window: &mut Window,
20814        cx: &mut Context<Self>,
20815    ) -> Option<()> {
20816        let blame = self.blame.as_ref()?;
20817        let snapshot = self.snapshot(window, cx);
20818        let cursor = self
20819            .selections
20820            .newest::<Point>(&snapshot.display_snapshot)
20821            .head();
20822        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20823        let (_, blame_entry) = blame
20824            .update(cx, |blame, cx| {
20825                blame
20826                    .blame_for_rows(
20827                        &[RowInfo {
20828                            buffer_id: Some(buffer.remote_id()),
20829                            buffer_row: Some(point.row),
20830                            ..Default::default()
20831                        }],
20832                        cx,
20833                    )
20834                    .next()
20835            })
20836            .flatten()?;
20837        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20838        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20839        let workspace = self.workspace()?.downgrade();
20840        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20841        None
20842    }
20843
20844    pub fn git_blame_inline_enabled(&self) -> bool {
20845        self.git_blame_inline_enabled
20846    }
20847
20848    pub fn toggle_selection_menu(
20849        &mut self,
20850        _: &ToggleSelectionMenu,
20851        _: &mut Window,
20852        cx: &mut Context<Self>,
20853    ) {
20854        self.show_selection_menu = self
20855            .show_selection_menu
20856            .map(|show_selections_menu| !show_selections_menu)
20857            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20858
20859        cx.notify();
20860    }
20861
20862    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20863        self.show_selection_menu
20864            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20865    }
20866
20867    fn start_git_blame(
20868        &mut self,
20869        user_triggered: bool,
20870        window: &mut Window,
20871        cx: &mut Context<Self>,
20872    ) {
20873        if let Some(project) = self.project() {
20874            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20875                && buffer.read(cx).file().is_none()
20876            {
20877                return;
20878            }
20879
20880            let focused = self.focus_handle(cx).contains_focused(window, cx);
20881
20882            let project = project.clone();
20883            let blame = cx
20884                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20885            self.blame_subscription =
20886                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20887            self.blame = Some(blame);
20888        }
20889    }
20890
20891    fn toggle_git_blame_inline_internal(
20892        &mut self,
20893        user_triggered: bool,
20894        window: &mut Window,
20895        cx: &mut Context<Self>,
20896    ) {
20897        if self.git_blame_inline_enabled {
20898            self.git_blame_inline_enabled = false;
20899            self.show_git_blame_inline = false;
20900            self.show_git_blame_inline_delay_task.take();
20901        } else {
20902            self.git_blame_inline_enabled = true;
20903            self.start_git_blame_inline(user_triggered, window, cx);
20904        }
20905
20906        cx.notify();
20907    }
20908
20909    fn start_git_blame_inline(
20910        &mut self,
20911        user_triggered: bool,
20912        window: &mut Window,
20913        cx: &mut Context<Self>,
20914    ) {
20915        self.start_git_blame(user_triggered, window, cx);
20916
20917        if ProjectSettings::get_global(cx)
20918            .git
20919            .inline_blame_delay()
20920            .is_some()
20921        {
20922            self.start_inline_blame_timer(window, cx);
20923        } else {
20924            self.show_git_blame_inline = true
20925        }
20926    }
20927
20928    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20929        self.blame.as_ref()
20930    }
20931
20932    pub fn show_git_blame_gutter(&self) -> bool {
20933        self.show_git_blame_gutter
20934    }
20935
20936    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20937        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20938    }
20939
20940    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20941        self.show_git_blame_inline
20942            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20943            && !self.newest_selection_head_on_empty_line(cx)
20944            && self.has_blame_entries(cx)
20945    }
20946
20947    fn has_blame_entries(&self, cx: &App) -> bool {
20948        self.blame()
20949            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20950    }
20951
20952    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20953        let cursor_anchor = self.selections.newest_anchor().head();
20954
20955        let snapshot = self.buffer.read(cx).snapshot(cx);
20956        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20957
20958        snapshot.line_len(buffer_row) == 0
20959    }
20960
20961    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20962        let buffer_and_selection = maybe!({
20963            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20964            let selection_range = selection.range();
20965
20966            let multi_buffer = self.buffer().read(cx);
20967            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20968            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20969
20970            let (buffer, range, _) = if selection.reversed {
20971                buffer_ranges.first()
20972            } else {
20973                buffer_ranges.last()
20974            }?;
20975
20976            let selection = text::ToPoint::to_point(&range.start, buffer).row
20977                ..text::ToPoint::to_point(&range.end, buffer).row;
20978            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20979        });
20980
20981        let Some((buffer, selection)) = buffer_and_selection else {
20982            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20983        };
20984
20985        let Some(project) = self.project() else {
20986            return Task::ready(Err(anyhow!("editor does not have project")));
20987        };
20988
20989        project.update(cx, |project, cx| {
20990            project.get_permalink_to_line(&buffer, selection, cx)
20991        })
20992    }
20993
20994    pub fn copy_permalink_to_line(
20995        &mut self,
20996        _: &CopyPermalinkToLine,
20997        window: &mut Window,
20998        cx: &mut Context<Self>,
20999    ) {
21000        let permalink_task = self.get_permalink_to_line(cx);
21001        let workspace = self.workspace();
21002
21003        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21004            Ok(permalink) => {
21005                cx.update(|_, cx| {
21006                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21007                })
21008                .ok();
21009            }
21010            Err(err) => {
21011                let message = format!("Failed to copy permalink: {err}");
21012
21013                anyhow::Result::<()>::Err(err).log_err();
21014
21015                if let Some(workspace) = workspace {
21016                    workspace
21017                        .update_in(cx, |workspace, _, cx| {
21018                            struct CopyPermalinkToLine;
21019
21020                            workspace.show_toast(
21021                                Toast::new(
21022                                    NotificationId::unique::<CopyPermalinkToLine>(),
21023                                    message,
21024                                ),
21025                                cx,
21026                            )
21027                        })
21028                        .ok();
21029                }
21030            }
21031        })
21032        .detach();
21033    }
21034
21035    pub fn copy_file_location(
21036        &mut self,
21037        _: &CopyFileLocation,
21038        _: &mut Window,
21039        cx: &mut Context<Self>,
21040    ) {
21041        let selection = self
21042            .selections
21043            .newest::<Point>(&self.display_snapshot(cx))
21044            .start
21045            .row
21046            + 1;
21047        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21048            let project = self.project()?.read(cx);
21049            let file = buffer.read(cx).file()?;
21050            let path = file.path().display(project.path_style(cx));
21051
21052            Some(format!("{path}:{selection}"))
21053        }) {
21054            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21055        }
21056    }
21057
21058    pub fn open_permalink_to_line(
21059        &mut self,
21060        _: &OpenPermalinkToLine,
21061        window: &mut Window,
21062        cx: &mut Context<Self>,
21063    ) {
21064        let permalink_task = self.get_permalink_to_line(cx);
21065        let workspace = self.workspace();
21066
21067        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21068            Ok(permalink) => {
21069                cx.update(|_, cx| {
21070                    cx.open_url(permalink.as_ref());
21071                })
21072                .ok();
21073            }
21074            Err(err) => {
21075                let message = format!("Failed to open permalink: {err}");
21076
21077                anyhow::Result::<()>::Err(err).log_err();
21078
21079                if let Some(workspace) = workspace {
21080                    workspace
21081                        .update(cx, |workspace, cx| {
21082                            struct OpenPermalinkToLine;
21083
21084                            workspace.show_toast(
21085                                Toast::new(
21086                                    NotificationId::unique::<OpenPermalinkToLine>(),
21087                                    message,
21088                                ),
21089                                cx,
21090                            )
21091                        })
21092                        .ok();
21093                }
21094            }
21095        })
21096        .detach();
21097    }
21098
21099    pub fn insert_uuid_v4(
21100        &mut self,
21101        _: &InsertUuidV4,
21102        window: &mut Window,
21103        cx: &mut Context<Self>,
21104    ) {
21105        self.insert_uuid(UuidVersion::V4, window, cx);
21106    }
21107
21108    pub fn insert_uuid_v7(
21109        &mut self,
21110        _: &InsertUuidV7,
21111        window: &mut Window,
21112        cx: &mut Context<Self>,
21113    ) {
21114        self.insert_uuid(UuidVersion::V7, window, cx);
21115    }
21116
21117    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21119        self.transact(window, cx, |this, window, cx| {
21120            let edits = this
21121                .selections
21122                .all::<Point>(&this.display_snapshot(cx))
21123                .into_iter()
21124                .map(|selection| {
21125                    let uuid = match version {
21126                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21127                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21128                    };
21129
21130                    (selection.range(), uuid.to_string())
21131                });
21132            this.edit(edits, cx);
21133            this.refresh_edit_prediction(true, false, window, cx);
21134        });
21135    }
21136
21137    pub fn open_selections_in_multibuffer(
21138        &mut self,
21139        _: &OpenSelectionsInMultibuffer,
21140        window: &mut Window,
21141        cx: &mut Context<Self>,
21142    ) {
21143        let multibuffer = self.buffer.read(cx);
21144
21145        let Some(buffer) = multibuffer.as_singleton() else {
21146            return;
21147        };
21148
21149        let Some(workspace) = self.workspace() else {
21150            return;
21151        };
21152
21153        let title = multibuffer.title(cx).to_string();
21154
21155        let locations = self
21156            .selections
21157            .all_anchors(&self.display_snapshot(cx))
21158            .iter()
21159            .map(|selection| {
21160                (
21161                    buffer.clone(),
21162                    (selection.start.text_anchor..selection.end.text_anchor)
21163                        .to_point(buffer.read(cx)),
21164                )
21165            })
21166            .into_group_map();
21167
21168        cx.spawn_in(window, async move |_, cx| {
21169            workspace.update_in(cx, |workspace, window, cx| {
21170                Self::open_locations_in_multibuffer(
21171                    workspace,
21172                    locations,
21173                    format!("Selections for '{title}'"),
21174                    false,
21175                    false,
21176                    MultibufferSelectionMode::All,
21177                    window,
21178                    cx,
21179                );
21180            })
21181        })
21182        .detach();
21183    }
21184
21185    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21186    /// last highlight added will be used.
21187    ///
21188    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21189    pub fn highlight_rows<T: 'static>(
21190        &mut self,
21191        range: Range<Anchor>,
21192        color: Hsla,
21193        options: RowHighlightOptions,
21194        cx: &mut Context<Self>,
21195    ) {
21196        let snapshot = self.buffer().read(cx).snapshot(cx);
21197        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21198        let ix = row_highlights.binary_search_by(|highlight| {
21199            Ordering::Equal
21200                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21201                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21202        });
21203
21204        if let Err(mut ix) = ix {
21205            let index = post_inc(&mut self.highlight_order);
21206
21207            // If this range intersects with the preceding highlight, then merge it with
21208            // the preceding highlight. Otherwise insert a new highlight.
21209            let mut merged = false;
21210            if ix > 0 {
21211                let prev_highlight = &mut row_highlights[ix - 1];
21212                if prev_highlight
21213                    .range
21214                    .end
21215                    .cmp(&range.start, &snapshot)
21216                    .is_ge()
21217                {
21218                    ix -= 1;
21219                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21220                        prev_highlight.range.end = range.end;
21221                    }
21222                    merged = true;
21223                    prev_highlight.index = index;
21224                    prev_highlight.color = color;
21225                    prev_highlight.options = options;
21226                }
21227            }
21228
21229            if !merged {
21230                row_highlights.insert(
21231                    ix,
21232                    RowHighlight {
21233                        range,
21234                        index,
21235                        color,
21236                        options,
21237                        type_id: TypeId::of::<T>(),
21238                    },
21239                );
21240            }
21241
21242            // If any of the following highlights intersect with this one, merge them.
21243            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21244                let highlight = &row_highlights[ix];
21245                if next_highlight
21246                    .range
21247                    .start
21248                    .cmp(&highlight.range.end, &snapshot)
21249                    .is_le()
21250                {
21251                    if next_highlight
21252                        .range
21253                        .end
21254                        .cmp(&highlight.range.end, &snapshot)
21255                        .is_gt()
21256                    {
21257                        row_highlights[ix].range.end = next_highlight.range.end;
21258                    }
21259                    row_highlights.remove(ix + 1);
21260                } else {
21261                    break;
21262                }
21263            }
21264        }
21265    }
21266
21267    /// Remove any highlighted row ranges of the given type that intersect the
21268    /// given ranges.
21269    pub fn remove_highlighted_rows<T: 'static>(
21270        &mut self,
21271        ranges_to_remove: Vec<Range<Anchor>>,
21272        cx: &mut Context<Self>,
21273    ) {
21274        let snapshot = self.buffer().read(cx).snapshot(cx);
21275        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21276        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21277        row_highlights.retain(|highlight| {
21278            while let Some(range_to_remove) = ranges_to_remove.peek() {
21279                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21280                    Ordering::Less | Ordering::Equal => {
21281                        ranges_to_remove.next();
21282                    }
21283                    Ordering::Greater => {
21284                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21285                            Ordering::Less | Ordering::Equal => {
21286                                return false;
21287                            }
21288                            Ordering::Greater => break,
21289                        }
21290                    }
21291                }
21292            }
21293
21294            true
21295        })
21296    }
21297
21298    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21299    pub fn clear_row_highlights<T: 'static>(&mut self) {
21300        self.highlighted_rows.remove(&TypeId::of::<T>());
21301    }
21302
21303    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21304    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21305        self.highlighted_rows
21306            .get(&TypeId::of::<T>())
21307            .map_or(&[] as &[_], |vec| vec.as_slice())
21308            .iter()
21309            .map(|highlight| (highlight.range.clone(), highlight.color))
21310    }
21311
21312    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21313    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21314    /// Allows to ignore certain kinds of highlights.
21315    pub fn highlighted_display_rows(
21316        &self,
21317        window: &mut Window,
21318        cx: &mut App,
21319    ) -> BTreeMap<DisplayRow, LineHighlight> {
21320        let snapshot = self.snapshot(window, cx);
21321        let mut used_highlight_orders = HashMap::default();
21322        self.highlighted_rows
21323            .iter()
21324            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21325            .fold(
21326                BTreeMap::<DisplayRow, LineHighlight>::new(),
21327                |mut unique_rows, highlight| {
21328                    let start = highlight.range.start.to_display_point(&snapshot);
21329                    let end = highlight.range.end.to_display_point(&snapshot);
21330                    let start_row = start.row().0;
21331                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21332                    {
21333                        end.row().0.saturating_sub(1)
21334                    } else {
21335                        end.row().0
21336                    };
21337                    for row in start_row..=end_row {
21338                        let used_index =
21339                            used_highlight_orders.entry(row).or_insert(highlight.index);
21340                        if highlight.index >= *used_index {
21341                            *used_index = highlight.index;
21342                            unique_rows.insert(
21343                                DisplayRow(row),
21344                                LineHighlight {
21345                                    include_gutter: highlight.options.include_gutter,
21346                                    border: None,
21347                                    background: highlight.color.into(),
21348                                    type_id: Some(highlight.type_id),
21349                                },
21350                            );
21351                        }
21352                    }
21353                    unique_rows
21354                },
21355            )
21356    }
21357
21358    pub fn highlighted_display_row_for_autoscroll(
21359        &self,
21360        snapshot: &DisplaySnapshot,
21361    ) -> Option<DisplayRow> {
21362        self.highlighted_rows
21363            .values()
21364            .flat_map(|highlighted_rows| highlighted_rows.iter())
21365            .filter_map(|highlight| {
21366                if highlight.options.autoscroll {
21367                    Some(highlight.range.start.to_display_point(snapshot).row())
21368                } else {
21369                    None
21370                }
21371            })
21372            .min()
21373    }
21374
21375    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21376        self.highlight_background::<SearchWithinRange>(
21377            ranges,
21378            |_, colors| colors.colors().editor_document_highlight_read_background,
21379            cx,
21380        )
21381    }
21382
21383    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21384        self.breadcrumb_header = Some(new_header);
21385    }
21386
21387    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21388        self.clear_background_highlights::<SearchWithinRange>(cx);
21389    }
21390
21391    pub fn highlight_background<T: 'static>(
21392        &mut self,
21393        ranges: &[Range<Anchor>],
21394        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21395        cx: &mut Context<Self>,
21396    ) {
21397        self.background_highlights.insert(
21398            HighlightKey::Type(TypeId::of::<T>()),
21399            (Arc::new(color_fetcher), Arc::from(ranges)),
21400        );
21401        self.scrollbar_marker_state.dirty = true;
21402        cx.notify();
21403    }
21404
21405    pub fn highlight_background_key<T: 'static>(
21406        &mut self,
21407        key: usize,
21408        ranges: &[Range<Anchor>],
21409        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21410        cx: &mut Context<Self>,
21411    ) {
21412        self.background_highlights.insert(
21413            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21414            (Arc::new(color_fetcher), Arc::from(ranges)),
21415        );
21416        self.scrollbar_marker_state.dirty = true;
21417        cx.notify();
21418    }
21419
21420    pub fn clear_background_highlights<T: 'static>(
21421        &mut self,
21422        cx: &mut Context<Self>,
21423    ) -> Option<BackgroundHighlight> {
21424        let text_highlights = self
21425            .background_highlights
21426            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21427        if !text_highlights.1.is_empty() {
21428            self.scrollbar_marker_state.dirty = true;
21429            cx.notify();
21430        }
21431        Some(text_highlights)
21432    }
21433
21434    pub fn highlight_gutter<T: 'static>(
21435        &mut self,
21436        ranges: impl Into<Vec<Range<Anchor>>>,
21437        color_fetcher: fn(&App) -> Hsla,
21438        cx: &mut Context<Self>,
21439    ) {
21440        self.gutter_highlights
21441            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21442        cx.notify();
21443    }
21444
21445    pub fn clear_gutter_highlights<T: 'static>(
21446        &mut self,
21447        cx: &mut Context<Self>,
21448    ) -> Option<GutterHighlight> {
21449        cx.notify();
21450        self.gutter_highlights.remove(&TypeId::of::<T>())
21451    }
21452
21453    pub fn insert_gutter_highlight<T: 'static>(
21454        &mut self,
21455        range: Range<Anchor>,
21456        color_fetcher: fn(&App) -> Hsla,
21457        cx: &mut Context<Self>,
21458    ) {
21459        let snapshot = self.buffer().read(cx).snapshot(cx);
21460        let mut highlights = self
21461            .gutter_highlights
21462            .remove(&TypeId::of::<T>())
21463            .map(|(_, highlights)| highlights)
21464            .unwrap_or_default();
21465        let ix = highlights.binary_search_by(|highlight| {
21466            Ordering::Equal
21467                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21468                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21469        });
21470        if let Err(ix) = ix {
21471            highlights.insert(ix, range);
21472        }
21473        self.gutter_highlights
21474            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21475    }
21476
21477    pub fn remove_gutter_highlights<T: 'static>(
21478        &mut self,
21479        ranges_to_remove: Vec<Range<Anchor>>,
21480        cx: &mut Context<Self>,
21481    ) {
21482        let snapshot = self.buffer().read(cx).snapshot(cx);
21483        let Some((color_fetcher, mut gutter_highlights)) =
21484            self.gutter_highlights.remove(&TypeId::of::<T>())
21485        else {
21486            return;
21487        };
21488        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21489        gutter_highlights.retain(|highlight| {
21490            while let Some(range_to_remove) = ranges_to_remove.peek() {
21491                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21492                    Ordering::Less | Ordering::Equal => {
21493                        ranges_to_remove.next();
21494                    }
21495                    Ordering::Greater => {
21496                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21497                            Ordering::Less | Ordering::Equal => {
21498                                return false;
21499                            }
21500                            Ordering::Greater => break,
21501                        }
21502                    }
21503                }
21504            }
21505
21506            true
21507        });
21508        self.gutter_highlights
21509            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21510    }
21511
21512    #[cfg(feature = "test-support")]
21513    pub fn all_text_highlights(
21514        &self,
21515        window: &mut Window,
21516        cx: &mut Context<Self>,
21517    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21518        let snapshot = self.snapshot(window, cx);
21519        self.display_map.update(cx, |display_map, _| {
21520            display_map
21521                .all_text_highlights()
21522                .map(|highlight| {
21523                    let (style, ranges) = highlight.as_ref();
21524                    (
21525                        *style,
21526                        ranges
21527                            .iter()
21528                            .map(|range| range.clone().to_display_points(&snapshot))
21529                            .collect(),
21530                    )
21531                })
21532                .collect()
21533        })
21534    }
21535
21536    #[cfg(feature = "test-support")]
21537    pub fn all_text_background_highlights(
21538        &self,
21539        window: &mut Window,
21540        cx: &mut Context<Self>,
21541    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21542        let snapshot = self.snapshot(window, cx);
21543        let buffer = &snapshot.buffer_snapshot();
21544        let start = buffer.anchor_before(MultiBufferOffset(0));
21545        let end = buffer.anchor_after(buffer.len());
21546        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21547    }
21548
21549    #[cfg(any(test, feature = "test-support"))]
21550    pub fn sorted_background_highlights_in_range(
21551        &self,
21552        search_range: Range<Anchor>,
21553        display_snapshot: &DisplaySnapshot,
21554        theme: &Theme,
21555    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21556        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21557        res.sort_by(|a, b| {
21558            a.0.start
21559                .cmp(&b.0.start)
21560                .then_with(|| a.0.end.cmp(&b.0.end))
21561                .then_with(|| a.1.cmp(&b.1))
21562        });
21563        res
21564    }
21565
21566    #[cfg(feature = "test-support")]
21567    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21568        let snapshot = self.buffer().read(cx).snapshot(cx);
21569
21570        let highlights = self
21571            .background_highlights
21572            .get(&HighlightKey::Type(TypeId::of::<
21573                items::BufferSearchHighlights,
21574            >()));
21575
21576        if let Some((_color, ranges)) = highlights {
21577            ranges
21578                .iter()
21579                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21580                .collect_vec()
21581        } else {
21582            vec![]
21583        }
21584    }
21585
21586    fn document_highlights_for_position<'a>(
21587        &'a self,
21588        position: Anchor,
21589        buffer: &'a MultiBufferSnapshot,
21590    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21591        let read_highlights = self
21592            .background_highlights
21593            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21594            .map(|h| &h.1);
21595        let write_highlights = self
21596            .background_highlights
21597            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21598            .map(|h| &h.1);
21599        let left_position = position.bias_left(buffer);
21600        let right_position = position.bias_right(buffer);
21601        read_highlights
21602            .into_iter()
21603            .chain(write_highlights)
21604            .flat_map(move |ranges| {
21605                let start_ix = match ranges.binary_search_by(|probe| {
21606                    let cmp = probe.end.cmp(&left_position, buffer);
21607                    if cmp.is_ge() {
21608                        Ordering::Greater
21609                    } else {
21610                        Ordering::Less
21611                    }
21612                }) {
21613                    Ok(i) | Err(i) => i,
21614                };
21615
21616                ranges[start_ix..]
21617                    .iter()
21618                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21619            })
21620    }
21621
21622    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21623        self.background_highlights
21624            .get(&HighlightKey::Type(TypeId::of::<T>()))
21625            .is_some_and(|(_, highlights)| !highlights.is_empty())
21626    }
21627
21628    /// Returns all background highlights for a given range.
21629    ///
21630    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21631    pub fn background_highlights_in_range(
21632        &self,
21633        search_range: Range<Anchor>,
21634        display_snapshot: &DisplaySnapshot,
21635        theme: &Theme,
21636    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21637        let mut results = Vec::new();
21638        for (color_fetcher, ranges) in self.background_highlights.values() {
21639            let start_ix = match ranges.binary_search_by(|probe| {
21640                let cmp = probe
21641                    .end
21642                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21643                if cmp.is_gt() {
21644                    Ordering::Greater
21645                } else {
21646                    Ordering::Less
21647                }
21648            }) {
21649                Ok(i) | Err(i) => i,
21650            };
21651            for (index, range) in ranges[start_ix..].iter().enumerate() {
21652                if range
21653                    .start
21654                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21655                    .is_ge()
21656                {
21657                    break;
21658                }
21659
21660                let color = color_fetcher(&(start_ix + index), theme);
21661                let start = range.start.to_display_point(display_snapshot);
21662                let end = range.end.to_display_point(display_snapshot);
21663                results.push((start..end, color))
21664            }
21665        }
21666        results
21667    }
21668
21669    pub fn gutter_highlights_in_range(
21670        &self,
21671        search_range: Range<Anchor>,
21672        display_snapshot: &DisplaySnapshot,
21673        cx: &App,
21674    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21675        let mut results = Vec::new();
21676        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21677            let color = color_fetcher(cx);
21678            let start_ix = match ranges.binary_search_by(|probe| {
21679                let cmp = probe
21680                    .end
21681                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21682                if cmp.is_gt() {
21683                    Ordering::Greater
21684                } else {
21685                    Ordering::Less
21686                }
21687            }) {
21688                Ok(i) | Err(i) => i,
21689            };
21690            for range in &ranges[start_ix..] {
21691                if range
21692                    .start
21693                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21694                    .is_ge()
21695                {
21696                    break;
21697                }
21698
21699                let start = range.start.to_display_point(display_snapshot);
21700                let end = range.end.to_display_point(display_snapshot);
21701                results.push((start..end, color))
21702            }
21703        }
21704        results
21705    }
21706
21707    /// Get the text ranges corresponding to the redaction query
21708    pub fn redacted_ranges(
21709        &self,
21710        search_range: Range<Anchor>,
21711        display_snapshot: &DisplaySnapshot,
21712        cx: &App,
21713    ) -> Vec<Range<DisplayPoint>> {
21714        display_snapshot
21715            .buffer_snapshot()
21716            .redacted_ranges(search_range, |file| {
21717                if let Some(file) = file {
21718                    file.is_private()
21719                        && EditorSettings::get(
21720                            Some(SettingsLocation {
21721                                worktree_id: file.worktree_id(cx),
21722                                path: file.path().as_ref(),
21723                            }),
21724                            cx,
21725                        )
21726                        .redact_private_values
21727                } else {
21728                    false
21729                }
21730            })
21731            .map(|range| {
21732                range.start.to_display_point(display_snapshot)
21733                    ..range.end.to_display_point(display_snapshot)
21734            })
21735            .collect()
21736    }
21737
21738    pub fn highlight_text_key<T: 'static>(
21739        &mut self,
21740        key: usize,
21741        ranges: Vec<Range<Anchor>>,
21742        style: HighlightStyle,
21743        merge: bool,
21744        cx: &mut Context<Self>,
21745    ) {
21746        self.display_map.update(cx, |map, cx| {
21747            map.highlight_text(
21748                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21749                ranges,
21750                style,
21751                merge,
21752                cx,
21753            );
21754        });
21755        cx.notify();
21756    }
21757
21758    pub fn highlight_text<T: 'static>(
21759        &mut self,
21760        ranges: Vec<Range<Anchor>>,
21761        style: HighlightStyle,
21762        cx: &mut Context<Self>,
21763    ) {
21764        self.display_map.update(cx, |map, cx| {
21765            map.highlight_text(
21766                HighlightKey::Type(TypeId::of::<T>()),
21767                ranges,
21768                style,
21769                false,
21770                cx,
21771            )
21772        });
21773        cx.notify();
21774    }
21775
21776    pub fn text_highlights<'a, T: 'static>(
21777        &'a self,
21778        cx: &'a App,
21779    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21780        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21781    }
21782
21783    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21784        let cleared = self
21785            .display_map
21786            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21787        if cleared {
21788            cx.notify();
21789        }
21790    }
21791
21792    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21793        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21794            && self.focus_handle.is_focused(window)
21795    }
21796
21797    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21798        self.show_cursor_when_unfocused = is_enabled;
21799        cx.notify();
21800    }
21801
21802    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21803        cx.notify();
21804    }
21805
21806    fn on_debug_session_event(
21807        &mut self,
21808        _session: Entity<Session>,
21809        event: &SessionEvent,
21810        cx: &mut Context<Self>,
21811    ) {
21812        if let SessionEvent::InvalidateInlineValue = event {
21813            self.refresh_inline_values(cx);
21814        }
21815    }
21816
21817    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21818        let Some(project) = self.project.clone() else {
21819            return;
21820        };
21821
21822        if !self.inline_value_cache.enabled {
21823            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21824            self.splice_inlays(&inlays, Vec::new(), cx);
21825            return;
21826        }
21827
21828        let current_execution_position = self
21829            .highlighted_rows
21830            .get(&TypeId::of::<ActiveDebugLine>())
21831            .and_then(|lines| lines.last().map(|line| line.range.end));
21832
21833        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21834            let inline_values = editor
21835                .update(cx, |editor, cx| {
21836                    let Some(current_execution_position) = current_execution_position else {
21837                        return Some(Task::ready(Ok(Vec::new())));
21838                    };
21839
21840                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21841                        let snapshot = buffer.snapshot(cx);
21842
21843                        let excerpt = snapshot.excerpt_containing(
21844                            current_execution_position..current_execution_position,
21845                        )?;
21846
21847                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21848                    })?;
21849
21850                    let range =
21851                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21852
21853                    project.inline_values(buffer, range, cx)
21854                })
21855                .ok()
21856                .flatten()?
21857                .await
21858                .context("refreshing debugger inlays")
21859                .log_err()?;
21860
21861            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21862
21863            for (buffer_id, inline_value) in inline_values
21864                .into_iter()
21865                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21866            {
21867                buffer_inline_values
21868                    .entry(buffer_id)
21869                    .or_default()
21870                    .push(inline_value);
21871            }
21872
21873            editor
21874                .update(cx, |editor, cx| {
21875                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21876                    let mut new_inlays = Vec::default();
21877
21878                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21879                        let buffer_id = buffer_snapshot.remote_id();
21880                        buffer_inline_values
21881                            .get(&buffer_id)
21882                            .into_iter()
21883                            .flatten()
21884                            .for_each(|hint| {
21885                                let inlay = Inlay::debugger(
21886                                    post_inc(&mut editor.next_inlay_id),
21887                                    Anchor::in_buffer(excerpt_id, hint.position),
21888                                    hint.text(),
21889                                );
21890                                if !inlay.text().chars().contains(&'\n') {
21891                                    new_inlays.push(inlay);
21892                                }
21893                            });
21894                    }
21895
21896                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21897                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21898
21899                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21900                })
21901                .ok()?;
21902            Some(())
21903        });
21904    }
21905
21906    fn on_buffer_event(
21907        &mut self,
21908        multibuffer: &Entity<MultiBuffer>,
21909        event: &multi_buffer::Event,
21910        window: &mut Window,
21911        cx: &mut Context<Self>,
21912    ) {
21913        match event {
21914            multi_buffer::Event::Edited { edited_buffer } => {
21915                self.scrollbar_marker_state.dirty = true;
21916                self.active_indent_guides_state.dirty = true;
21917                self.refresh_active_diagnostics(cx);
21918                self.refresh_code_actions(window, cx);
21919                self.refresh_single_line_folds(window, cx);
21920                self.refresh_matching_bracket_highlights(window, cx);
21921                if self.has_active_edit_prediction() {
21922                    self.update_visible_edit_prediction(window, cx);
21923                }
21924
21925                if let Some(buffer) = edited_buffer {
21926                    if buffer.read(cx).file().is_none() {
21927                        cx.emit(EditorEvent::TitleChanged);
21928                    }
21929
21930                    if self.project.is_some() {
21931                        let buffer_id = buffer.read(cx).remote_id();
21932                        self.register_buffer(buffer_id, cx);
21933                        self.update_lsp_data(Some(buffer_id), window, cx);
21934                        self.refresh_inlay_hints(
21935                            InlayHintRefreshReason::BufferEdited(buffer_id),
21936                            cx,
21937                        );
21938                    }
21939                }
21940
21941                cx.emit(EditorEvent::BufferEdited);
21942                cx.emit(SearchEvent::MatchesInvalidated);
21943
21944                let Some(project) = &self.project else { return };
21945                let (telemetry, is_via_ssh) = {
21946                    let project = project.read(cx);
21947                    let telemetry = project.client().telemetry().clone();
21948                    let is_via_ssh = project.is_via_remote_server();
21949                    (telemetry, is_via_ssh)
21950                };
21951                telemetry.log_edit_event("editor", is_via_ssh);
21952            }
21953            multi_buffer::Event::ExcerptsAdded {
21954                buffer,
21955                predecessor,
21956                excerpts,
21957            } => {
21958                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21959                let buffer_id = buffer.read(cx).remote_id();
21960                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21961                    && let Some(project) = &self.project
21962                {
21963                    update_uncommitted_diff_for_buffer(
21964                        cx.entity(),
21965                        project,
21966                        [buffer.clone()],
21967                        self.buffer.clone(),
21968                        cx,
21969                    )
21970                    .detach();
21971                }
21972                self.update_lsp_data(Some(buffer_id), window, cx);
21973                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21974                self.colorize_brackets(false, cx);
21975                cx.emit(EditorEvent::ExcerptsAdded {
21976                    buffer: buffer.clone(),
21977                    predecessor: *predecessor,
21978                    excerpts: excerpts.clone(),
21979                });
21980            }
21981            multi_buffer::Event::ExcerptsRemoved {
21982                ids,
21983                removed_buffer_ids,
21984            } => {
21985                if let Some(inlay_hints) = &mut self.inlay_hints {
21986                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21987                }
21988                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21989                for buffer_id in removed_buffer_ids {
21990                    self.registered_buffers.remove(buffer_id);
21991                }
21992                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21993                cx.emit(EditorEvent::ExcerptsRemoved {
21994                    ids: ids.clone(),
21995                    removed_buffer_ids: removed_buffer_ids.clone(),
21996                });
21997            }
21998            multi_buffer::Event::ExcerptsEdited {
21999                excerpt_ids,
22000                buffer_ids,
22001            } => {
22002                self.display_map.update(cx, |map, cx| {
22003                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22004                });
22005                cx.emit(EditorEvent::ExcerptsEdited {
22006                    ids: excerpt_ids.clone(),
22007                });
22008            }
22009            multi_buffer::Event::ExcerptsExpanded { ids } => {
22010                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22011                self.refresh_document_highlights(cx);
22012                for id in ids {
22013                    self.fetched_tree_sitter_chunks.remove(id);
22014                }
22015                self.colorize_brackets(false, cx);
22016                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22017            }
22018            multi_buffer::Event::Reparsed(buffer_id) => {
22019                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22020                self.refresh_selected_text_highlights(true, window, cx);
22021                self.colorize_brackets(true, cx);
22022                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22023
22024                cx.emit(EditorEvent::Reparsed(*buffer_id));
22025            }
22026            multi_buffer::Event::DiffHunksToggled => {
22027                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22028            }
22029            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22030                if !is_fresh_language {
22031                    self.registered_buffers.remove(&buffer_id);
22032                }
22033                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22034                cx.emit(EditorEvent::Reparsed(*buffer_id));
22035                cx.notify();
22036            }
22037            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22038            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22039            multi_buffer::Event::FileHandleChanged
22040            | multi_buffer::Event::Reloaded
22041            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22042            multi_buffer::Event::DiagnosticsUpdated => {
22043                self.update_diagnostics_state(window, cx);
22044            }
22045            _ => {}
22046        };
22047    }
22048
22049    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22050        if !self.diagnostics_enabled() {
22051            return;
22052        }
22053        self.refresh_active_diagnostics(cx);
22054        self.refresh_inline_diagnostics(true, window, cx);
22055        self.scrollbar_marker_state.dirty = true;
22056        cx.notify();
22057    }
22058
22059    pub fn start_temporary_diff_override(&mut self) {
22060        self.load_diff_task.take();
22061        self.temporary_diff_override = true;
22062    }
22063
22064    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22065        self.temporary_diff_override = false;
22066        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22067        self.buffer.update(cx, |buffer, cx| {
22068            buffer.set_all_diff_hunks_collapsed(cx);
22069        });
22070
22071        if let Some(project) = self.project.clone() {
22072            self.load_diff_task = Some(
22073                update_uncommitted_diff_for_buffer(
22074                    cx.entity(),
22075                    &project,
22076                    self.buffer.read(cx).all_buffers(),
22077                    self.buffer.clone(),
22078                    cx,
22079                )
22080                .shared(),
22081            );
22082        }
22083    }
22084
22085    fn on_display_map_changed(
22086        &mut self,
22087        _: Entity<DisplayMap>,
22088        _: &mut Window,
22089        cx: &mut Context<Self>,
22090    ) {
22091        cx.notify();
22092    }
22093
22094    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22095        if !self.mode.is_full() {
22096            return None;
22097        }
22098
22099        let theme_settings = theme::ThemeSettings::get_global(cx);
22100        let theme = cx.theme();
22101        let accent_colors = theme.accents().clone();
22102
22103        let accent_overrides = theme_settings
22104            .theme_overrides
22105            .get(theme.name.as_ref())
22106            .map(|theme_style| &theme_style.accents)
22107            .into_iter()
22108            .flatten()
22109            .chain(
22110                theme_settings
22111                    .experimental_theme_overrides
22112                    .as_ref()
22113                    .map(|overrides| &overrides.accents)
22114                    .into_iter()
22115                    .flatten(),
22116            )
22117            .flat_map(|accent| accent.0.clone())
22118            .collect();
22119
22120        Some(AccentData {
22121            colors: accent_colors,
22122            overrides: accent_overrides,
22123        })
22124    }
22125
22126    fn fetch_applicable_language_settings(
22127        &self,
22128        cx: &App,
22129    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22130        if !self.mode.is_full() {
22131            return HashMap::default();
22132        }
22133
22134        self.buffer().read(cx).all_buffers().into_iter().fold(
22135            HashMap::default(),
22136            |mut acc, buffer| {
22137                let buffer = buffer.read(cx);
22138                let language = buffer.language().map(|language| language.name());
22139                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22140                    let file = buffer.file();
22141                    v.insert(language_settings(language, file, cx).into_owned());
22142                }
22143                acc
22144            },
22145        )
22146    }
22147
22148    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22149        let new_language_settings = self.fetch_applicable_language_settings(cx);
22150        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22151        self.applicable_language_settings = new_language_settings;
22152
22153        let new_accents = self.fetch_accent_data(cx);
22154        let accents_changed = new_accents != self.accent_data;
22155        self.accent_data = new_accents;
22156
22157        if self.diagnostics_enabled() {
22158            let new_severity = EditorSettings::get_global(cx)
22159                .diagnostics_max_severity
22160                .unwrap_or(DiagnosticSeverity::Hint);
22161            self.set_max_diagnostics_severity(new_severity, cx);
22162        }
22163        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22164        self.update_edit_prediction_settings(cx);
22165        self.refresh_edit_prediction(true, false, window, cx);
22166        self.refresh_inline_values(cx);
22167        self.refresh_inlay_hints(
22168            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22169                self.selections.newest_anchor().head(),
22170                &self.buffer.read(cx).snapshot(cx),
22171                cx,
22172            )),
22173            cx,
22174        );
22175
22176        let old_cursor_shape = self.cursor_shape;
22177        let old_show_breadcrumbs = self.show_breadcrumbs;
22178
22179        {
22180            let editor_settings = EditorSettings::get_global(cx);
22181            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22182            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22183            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22184            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22185        }
22186
22187        if old_cursor_shape != self.cursor_shape {
22188            cx.emit(EditorEvent::CursorShapeChanged);
22189        }
22190
22191        if old_show_breadcrumbs != self.show_breadcrumbs {
22192            cx.emit(EditorEvent::BreadcrumbsChanged);
22193        }
22194
22195        let project_settings = ProjectSettings::get_global(cx);
22196        self.buffer_serialization = self
22197            .should_serialize_buffer()
22198            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22199
22200        if self.mode.is_full() {
22201            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22202            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22203            if self.show_inline_diagnostics != show_inline_diagnostics {
22204                self.show_inline_diagnostics = show_inline_diagnostics;
22205                self.refresh_inline_diagnostics(false, window, cx);
22206            }
22207
22208            if self.git_blame_inline_enabled != inline_blame_enabled {
22209                self.toggle_git_blame_inline_internal(false, window, cx);
22210            }
22211
22212            let minimap_settings = EditorSettings::get_global(cx).minimap;
22213            if self.minimap_visibility != MinimapVisibility::Disabled {
22214                if self.minimap_visibility.settings_visibility()
22215                    != minimap_settings.minimap_enabled()
22216                {
22217                    self.set_minimap_visibility(
22218                        MinimapVisibility::for_mode(self.mode(), cx),
22219                        window,
22220                        cx,
22221                    );
22222                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22223                    minimap_entity.update(cx, |minimap_editor, cx| {
22224                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22225                    })
22226                }
22227            }
22228
22229            if language_settings_changed || accents_changed {
22230                self.colorize_brackets(true, cx);
22231            }
22232
22233            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22234                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22235            }) {
22236                if !inlay_splice.is_empty() {
22237                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22238                }
22239                self.refresh_colors_for_visible_range(None, window, cx);
22240            }
22241        }
22242
22243        cx.notify();
22244    }
22245
22246    pub fn set_searchable(&mut self, searchable: bool) {
22247        self.searchable = searchable;
22248    }
22249
22250    pub fn searchable(&self) -> bool {
22251        self.searchable
22252    }
22253
22254    pub fn open_excerpts_in_split(
22255        &mut self,
22256        _: &OpenExcerptsSplit,
22257        window: &mut Window,
22258        cx: &mut Context<Self>,
22259    ) {
22260        self.open_excerpts_common(None, true, window, cx)
22261    }
22262
22263    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22264        self.open_excerpts_common(None, false, window, cx)
22265    }
22266
22267    fn open_excerpts_common(
22268        &mut self,
22269        jump_data: Option<JumpData>,
22270        split: bool,
22271        window: &mut Window,
22272        cx: &mut Context<Self>,
22273    ) {
22274        let Some(workspace) = self.workspace() else {
22275            cx.propagate();
22276            return;
22277        };
22278
22279        if self.buffer.read(cx).is_singleton() {
22280            cx.propagate();
22281            return;
22282        }
22283
22284        let mut new_selections_by_buffer = HashMap::default();
22285        match &jump_data {
22286            Some(JumpData::MultiBufferPoint {
22287                excerpt_id,
22288                position,
22289                anchor,
22290                line_offset_from_top,
22291            }) => {
22292                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22293                if let Some(buffer) = multi_buffer_snapshot
22294                    .buffer_id_for_excerpt(*excerpt_id)
22295                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22296                {
22297                    let buffer_snapshot = buffer.read(cx).snapshot();
22298                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22299                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22300                    } else {
22301                        buffer_snapshot.clip_point(*position, Bias::Left)
22302                    };
22303                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22304                    new_selections_by_buffer.insert(
22305                        buffer,
22306                        (
22307                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22308                            Some(*line_offset_from_top),
22309                        ),
22310                    );
22311                }
22312            }
22313            Some(JumpData::MultiBufferRow {
22314                row,
22315                line_offset_from_top,
22316            }) => {
22317                let point = MultiBufferPoint::new(row.0, 0);
22318                if let Some((buffer, buffer_point, _)) =
22319                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22320                {
22321                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22322                    new_selections_by_buffer
22323                        .entry(buffer)
22324                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22325                        .0
22326                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22327                }
22328            }
22329            None => {
22330                let selections = self
22331                    .selections
22332                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22333                let multi_buffer = self.buffer.read(cx);
22334                for selection in selections {
22335                    for (snapshot, range, _, anchor) in multi_buffer
22336                        .snapshot(cx)
22337                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22338                    {
22339                        if let Some(anchor) = anchor {
22340                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22341                            else {
22342                                continue;
22343                            };
22344                            let offset = text::ToOffset::to_offset(
22345                                &anchor.text_anchor,
22346                                &buffer_handle.read(cx).snapshot(),
22347                            );
22348                            let range = BufferOffset(offset)..BufferOffset(offset);
22349                            new_selections_by_buffer
22350                                .entry(buffer_handle)
22351                                .or_insert((Vec::new(), None))
22352                                .0
22353                                .push(range)
22354                        } else {
22355                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22356                            else {
22357                                continue;
22358                            };
22359                            new_selections_by_buffer
22360                                .entry(buffer_handle)
22361                                .or_insert((Vec::new(), None))
22362                                .0
22363                                .push(range)
22364                        }
22365                    }
22366                }
22367            }
22368        }
22369
22370        new_selections_by_buffer
22371            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22372
22373        if new_selections_by_buffer.is_empty() {
22374            return;
22375        }
22376
22377        // We defer the pane interaction because we ourselves are a workspace item
22378        // and activating a new item causes the pane to call a method on us reentrantly,
22379        // which panics if we're on the stack.
22380        window.defer(cx, move |window, cx| {
22381            workspace.update(cx, |workspace, cx| {
22382                let pane = if split {
22383                    workspace.adjacent_pane(window, cx)
22384                } else {
22385                    workspace.active_pane().clone()
22386                };
22387
22388                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22389                    let buffer_read = buffer.read(cx);
22390                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22391                        (true, project::File::from_dyn(Some(file)).is_some())
22392                    } else {
22393                        (false, false)
22394                    };
22395
22396                    // If project file is none workspace.open_project_item will fail to open the excerpt
22397                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22398                    // so we check if there's a tab match in that case first
22399                    let editor = (!has_file || !is_project_file)
22400                        .then(|| {
22401                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22402                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22403                            // Instead, we try to activate the existing editor in the pane first.
22404                            let (editor, pane_item_index, pane_item_id) =
22405                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22406                                    let editor = item.downcast::<Editor>()?;
22407                                    let singleton_buffer =
22408                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22409                                    if singleton_buffer == buffer {
22410                                        Some((editor, i, item.item_id()))
22411                                    } else {
22412                                        None
22413                                    }
22414                                })?;
22415                            pane.update(cx, |pane, cx| {
22416                                pane.activate_item(pane_item_index, true, true, window, cx);
22417                                if !PreviewTabsSettings::get_global(cx)
22418                                    .enable_preview_from_multibuffer
22419                                {
22420                                    pane.unpreview_item_if_preview(pane_item_id);
22421                                }
22422                            });
22423                            Some(editor)
22424                        })
22425                        .flatten()
22426                        .unwrap_or_else(|| {
22427                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22428                                .enable_keep_preview_on_code_navigation;
22429                            let allow_new_preview =
22430                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22431                            workspace.open_project_item::<Self>(
22432                                pane.clone(),
22433                                buffer,
22434                                true,
22435                                true,
22436                                keep_old_preview,
22437                                allow_new_preview,
22438                                window,
22439                                cx,
22440                            )
22441                        });
22442
22443                    editor.update(cx, |editor, cx| {
22444                        if has_file && !is_project_file {
22445                            editor.set_read_only(true);
22446                        }
22447                        let autoscroll = match scroll_offset {
22448                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22449                            None => Autoscroll::newest(),
22450                        };
22451                        let nav_history = editor.nav_history.take();
22452                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22453                        let Some((&excerpt_id, _, buffer_snapshot)) =
22454                            multibuffer_snapshot.as_singleton()
22455                        else {
22456                            return;
22457                        };
22458                        editor.change_selections(
22459                            SelectionEffects::scroll(autoscroll),
22460                            window,
22461                            cx,
22462                            |s| {
22463                                s.select_ranges(ranges.into_iter().map(|range| {
22464                                    let range = buffer_snapshot.anchor_before(range.start)
22465                                        ..buffer_snapshot.anchor_after(range.end);
22466                                    multibuffer_snapshot
22467                                        .anchor_range_in_excerpt(excerpt_id, range)
22468                                        .unwrap()
22469                                }));
22470                            },
22471                        );
22472                        editor.nav_history = nav_history;
22473                    });
22474                }
22475            })
22476        });
22477    }
22478
22479    // Allow opening excerpts for buffers that either belong to the current project
22480    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22481    // are also supported so tests and other in-memory views keep working.
22482    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22483        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22484    }
22485
22486    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22487        let snapshot = self.buffer.read(cx).read(cx);
22488        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22489        Some(
22490            ranges
22491                .iter()
22492                .map(move |range| {
22493                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22494                })
22495                .collect(),
22496        )
22497    }
22498
22499    fn selection_replacement_ranges(
22500        &self,
22501        range: Range<MultiBufferOffsetUtf16>,
22502        cx: &mut App,
22503    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22504        let selections = self
22505            .selections
22506            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22507        let newest_selection = selections
22508            .iter()
22509            .max_by_key(|selection| selection.id)
22510            .unwrap();
22511        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22512        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22513        let snapshot = self.buffer.read(cx).read(cx);
22514        selections
22515            .into_iter()
22516            .map(|mut selection| {
22517                selection.start.0.0 =
22518                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22519                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22520                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22521                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22522            })
22523            .collect()
22524    }
22525
22526    fn report_editor_event(
22527        &self,
22528        reported_event: ReportEditorEvent,
22529        file_extension: Option<String>,
22530        cx: &App,
22531    ) {
22532        if cfg!(any(test, feature = "test-support")) {
22533            return;
22534        }
22535
22536        let Some(project) = &self.project else { return };
22537
22538        // If None, we are in a file without an extension
22539        let file = self
22540            .buffer
22541            .read(cx)
22542            .as_singleton()
22543            .and_then(|b| b.read(cx).file());
22544        let file_extension = file_extension.or(file
22545            .as_ref()
22546            .and_then(|file| Path::new(file.file_name(cx)).extension())
22547            .and_then(|e| e.to_str())
22548            .map(|a| a.to_string()));
22549
22550        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22551            .map(|vim_mode| vim_mode.0)
22552            .unwrap_or(false);
22553
22554        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22555        let copilot_enabled = edit_predictions_provider
22556            == language::language_settings::EditPredictionProvider::Copilot;
22557        let copilot_enabled_for_language = self
22558            .buffer
22559            .read(cx)
22560            .language_settings(cx)
22561            .show_edit_predictions;
22562
22563        let project = project.read(cx);
22564        let event_type = reported_event.event_type();
22565
22566        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22567            telemetry::event!(
22568                event_type,
22569                type = if auto_saved {"autosave"} else {"manual"},
22570                file_extension,
22571                vim_mode,
22572                copilot_enabled,
22573                copilot_enabled_for_language,
22574                edit_predictions_provider,
22575                is_via_ssh = project.is_via_remote_server(),
22576            );
22577        } else {
22578            telemetry::event!(
22579                event_type,
22580                file_extension,
22581                vim_mode,
22582                copilot_enabled,
22583                copilot_enabled_for_language,
22584                edit_predictions_provider,
22585                is_via_ssh = project.is_via_remote_server(),
22586            );
22587        };
22588    }
22589
22590    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22591    /// with each line being an array of {text, highlight} objects.
22592    fn copy_highlight_json(
22593        &mut self,
22594        _: &CopyHighlightJson,
22595        window: &mut Window,
22596        cx: &mut Context<Self>,
22597    ) {
22598        #[derive(Serialize)]
22599        struct Chunk<'a> {
22600            text: String,
22601            highlight: Option<&'a str>,
22602        }
22603
22604        let snapshot = self.buffer.read(cx).snapshot(cx);
22605        let range = self
22606            .selected_text_range(false, window, cx)
22607            .and_then(|selection| {
22608                if selection.range.is_empty() {
22609                    None
22610                } else {
22611                    Some(
22612                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22613                            selection.range.start,
22614                        )))
22615                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22616                                selection.range.end,
22617                            ))),
22618                    )
22619                }
22620            })
22621            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22622
22623        let chunks = snapshot.chunks(range, true);
22624        let mut lines = Vec::new();
22625        let mut line: VecDeque<Chunk> = VecDeque::new();
22626
22627        let Some(style) = self.style.as_ref() else {
22628            return;
22629        };
22630
22631        for chunk in chunks {
22632            let highlight = chunk
22633                .syntax_highlight_id
22634                .and_then(|id| id.name(&style.syntax));
22635            let mut chunk_lines = chunk.text.split('\n').peekable();
22636            while let Some(text) = chunk_lines.next() {
22637                let mut merged_with_last_token = false;
22638                if let Some(last_token) = line.back_mut()
22639                    && last_token.highlight == highlight
22640                {
22641                    last_token.text.push_str(text);
22642                    merged_with_last_token = true;
22643                }
22644
22645                if !merged_with_last_token {
22646                    line.push_back(Chunk {
22647                        text: text.into(),
22648                        highlight,
22649                    });
22650                }
22651
22652                if chunk_lines.peek().is_some() {
22653                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22654                        line.pop_front();
22655                    }
22656                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22657                        line.pop_back();
22658                    }
22659
22660                    lines.push(mem::take(&mut line));
22661                }
22662            }
22663        }
22664
22665        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22666            return;
22667        };
22668        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22669    }
22670
22671    pub fn open_context_menu(
22672        &mut self,
22673        _: &OpenContextMenu,
22674        window: &mut Window,
22675        cx: &mut Context<Self>,
22676    ) {
22677        self.request_autoscroll(Autoscroll::newest(), cx);
22678        let position = self
22679            .selections
22680            .newest_display(&self.display_snapshot(cx))
22681            .start;
22682        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22683    }
22684
22685    pub fn replay_insert_event(
22686        &mut self,
22687        text: &str,
22688        relative_utf16_range: Option<Range<isize>>,
22689        window: &mut Window,
22690        cx: &mut Context<Self>,
22691    ) {
22692        if !self.input_enabled {
22693            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22694            return;
22695        }
22696        if let Some(relative_utf16_range) = relative_utf16_range {
22697            let selections = self
22698                .selections
22699                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22700            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22701                let new_ranges = selections.into_iter().map(|range| {
22702                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22703                        range
22704                            .head()
22705                            .0
22706                            .0
22707                            .saturating_add_signed(relative_utf16_range.start),
22708                    ));
22709                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22710                        range
22711                            .head()
22712                            .0
22713                            .0
22714                            .saturating_add_signed(relative_utf16_range.end),
22715                    ));
22716                    start..end
22717                });
22718                s.select_ranges(new_ranges);
22719            });
22720        }
22721
22722        self.handle_input(text, window, cx);
22723    }
22724
22725    pub fn is_focused(&self, window: &Window) -> bool {
22726        self.focus_handle.is_focused(window)
22727    }
22728
22729    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22730        cx.emit(EditorEvent::Focused);
22731
22732        if let Some(descendant) = self
22733            .last_focused_descendant
22734            .take()
22735            .and_then(|descendant| descendant.upgrade())
22736        {
22737            window.focus(&descendant);
22738        } else {
22739            if let Some(blame) = self.blame.as_ref() {
22740                blame.update(cx, GitBlame::focus)
22741            }
22742
22743            self.blink_manager.update(cx, BlinkManager::enable);
22744            self.show_cursor_names(window, cx);
22745            self.buffer.update(cx, |buffer, cx| {
22746                buffer.finalize_last_transaction(cx);
22747                if self.leader_id.is_none() {
22748                    buffer.set_active_selections(
22749                        &self.selections.disjoint_anchors_arc(),
22750                        self.selections.line_mode(),
22751                        self.cursor_shape,
22752                        cx,
22753                    );
22754                }
22755            });
22756
22757            if let Some(position_map) = self.last_position_map.clone() {
22758                EditorElement::mouse_moved(
22759                    self,
22760                    &MouseMoveEvent {
22761                        position: window.mouse_position(),
22762                        pressed_button: None,
22763                        modifiers: window.modifiers(),
22764                    },
22765                    &position_map,
22766                    window,
22767                    cx,
22768                );
22769            }
22770        }
22771    }
22772
22773    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22774        cx.emit(EditorEvent::FocusedIn)
22775    }
22776
22777    fn handle_focus_out(
22778        &mut self,
22779        event: FocusOutEvent,
22780        _window: &mut Window,
22781        cx: &mut Context<Self>,
22782    ) {
22783        if event.blurred != self.focus_handle {
22784            self.last_focused_descendant = Some(event.blurred);
22785        }
22786        self.selection_drag_state = SelectionDragState::None;
22787        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22788    }
22789
22790    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22791        self.blink_manager.update(cx, BlinkManager::disable);
22792        self.buffer
22793            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22794
22795        if let Some(blame) = self.blame.as_ref() {
22796            blame.update(cx, GitBlame::blur)
22797        }
22798        if !self.hover_state.focused(window, cx) {
22799            hide_hover(self, cx);
22800        }
22801        if !self
22802            .context_menu
22803            .borrow()
22804            .as_ref()
22805            .is_some_and(|context_menu| context_menu.focused(window, cx))
22806        {
22807            self.hide_context_menu(window, cx);
22808        }
22809        self.take_active_edit_prediction(cx);
22810        cx.emit(EditorEvent::Blurred);
22811        cx.notify();
22812    }
22813
22814    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22815        let mut pending: String = window
22816            .pending_input_keystrokes()
22817            .into_iter()
22818            .flatten()
22819            .filter_map(|keystroke| keystroke.key_char.clone())
22820            .collect();
22821
22822        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22823            pending = "".to_string();
22824        }
22825
22826        let existing_pending = self
22827            .text_highlights::<PendingInput>(cx)
22828            .map(|(_, ranges)| ranges.to_vec());
22829        if existing_pending.is_none() && pending.is_empty() {
22830            return;
22831        }
22832        let transaction =
22833            self.transact(window, cx, |this, window, cx| {
22834                let selections = this
22835                    .selections
22836                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22837                let edits = selections
22838                    .iter()
22839                    .map(|selection| (selection.end..selection.end, pending.clone()));
22840                this.edit(edits, cx);
22841                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22842                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22843                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22844                    }));
22845                });
22846                if let Some(existing_ranges) = existing_pending {
22847                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22848                    this.edit(edits, cx);
22849                }
22850            });
22851
22852        let snapshot = self.snapshot(window, cx);
22853        let ranges = self
22854            .selections
22855            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22856            .into_iter()
22857            .map(|selection| {
22858                snapshot.buffer_snapshot().anchor_after(selection.end)
22859                    ..snapshot
22860                        .buffer_snapshot()
22861                        .anchor_before(selection.end + pending.len())
22862            })
22863            .collect();
22864
22865        if pending.is_empty() {
22866            self.clear_highlights::<PendingInput>(cx);
22867        } else {
22868            self.highlight_text::<PendingInput>(
22869                ranges,
22870                HighlightStyle {
22871                    underline: Some(UnderlineStyle {
22872                        thickness: px(1.),
22873                        color: None,
22874                        wavy: false,
22875                    }),
22876                    ..Default::default()
22877                },
22878                cx,
22879            );
22880        }
22881
22882        self.ime_transaction = self.ime_transaction.or(transaction);
22883        if let Some(transaction) = self.ime_transaction {
22884            self.buffer.update(cx, |buffer, cx| {
22885                buffer.group_until_transaction(transaction, cx);
22886            });
22887        }
22888
22889        if self.text_highlights::<PendingInput>(cx).is_none() {
22890            self.ime_transaction.take();
22891        }
22892    }
22893
22894    pub fn register_action_renderer(
22895        &mut self,
22896        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22897    ) -> Subscription {
22898        let id = self.next_editor_action_id.post_inc();
22899        self.editor_actions
22900            .borrow_mut()
22901            .insert(id, Box::new(listener));
22902
22903        let editor_actions = self.editor_actions.clone();
22904        Subscription::new(move || {
22905            editor_actions.borrow_mut().remove(&id);
22906        })
22907    }
22908
22909    pub fn register_action<A: Action>(
22910        &mut self,
22911        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22912    ) -> Subscription {
22913        let id = self.next_editor_action_id.post_inc();
22914        let listener = Arc::new(listener);
22915        self.editor_actions.borrow_mut().insert(
22916            id,
22917            Box::new(move |_, window, _| {
22918                let listener = listener.clone();
22919                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22920                    let action = action.downcast_ref().unwrap();
22921                    if phase == DispatchPhase::Bubble {
22922                        listener(action, window, cx)
22923                    }
22924                })
22925            }),
22926        );
22927
22928        let editor_actions = self.editor_actions.clone();
22929        Subscription::new(move || {
22930            editor_actions.borrow_mut().remove(&id);
22931        })
22932    }
22933
22934    pub fn file_header_size(&self) -> u32 {
22935        FILE_HEADER_HEIGHT
22936    }
22937
22938    pub fn restore(
22939        &mut self,
22940        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22941        window: &mut Window,
22942        cx: &mut Context<Self>,
22943    ) {
22944        let workspace = self.workspace();
22945        let project = self.project();
22946        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22947            let mut tasks = Vec::new();
22948            for (buffer_id, changes) in revert_changes {
22949                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22950                    buffer.update(cx, |buffer, cx| {
22951                        buffer.edit(
22952                            changes
22953                                .into_iter()
22954                                .map(|(range, text)| (range, text.to_string())),
22955                            None,
22956                            cx,
22957                        );
22958                    });
22959
22960                    if let Some(project) =
22961                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22962                    {
22963                        project.update(cx, |project, cx| {
22964                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22965                        })
22966                    }
22967                }
22968            }
22969            tasks
22970        });
22971        cx.spawn_in(window, async move |_, cx| {
22972            for (buffer, task) in save_tasks {
22973                let result = task.await;
22974                if result.is_err() {
22975                    let Some(path) = buffer
22976                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22977                        .ok()
22978                    else {
22979                        continue;
22980                    };
22981                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22982                        let Some(task) = cx
22983                            .update_window_entity(workspace, |workspace, window, cx| {
22984                                workspace
22985                                    .open_path_preview(path, None, false, false, false, window, cx)
22986                            })
22987                            .ok()
22988                        else {
22989                            continue;
22990                        };
22991                        task.await.log_err();
22992                    }
22993                }
22994            }
22995        })
22996        .detach();
22997        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22998            selections.refresh()
22999        });
23000    }
23001
23002    pub fn to_pixel_point(
23003        &mut self,
23004        source: multi_buffer::Anchor,
23005        editor_snapshot: &EditorSnapshot,
23006        window: &mut Window,
23007        cx: &App,
23008    ) -> Option<gpui::Point<Pixels>> {
23009        let source_point = source.to_display_point(editor_snapshot);
23010        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
23011    }
23012
23013    pub fn display_to_pixel_point(
23014        &mut self,
23015        source: DisplayPoint,
23016        editor_snapshot: &EditorSnapshot,
23017        window: &mut Window,
23018        cx: &App,
23019    ) -> Option<gpui::Point<Pixels>> {
23020        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
23021        let text_layout_details = self.text_layout_details(window);
23022        let scroll_top = text_layout_details
23023            .scroll_anchor
23024            .scroll_position(editor_snapshot)
23025            .y;
23026
23027        if source.row().as_f64() < scroll_top.floor() {
23028            return None;
23029        }
23030        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
23031        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
23032        Some(gpui::Point::new(source_x, source_y))
23033    }
23034
23035    pub fn has_visible_completions_menu(&self) -> bool {
23036        !self.edit_prediction_preview_is_active()
23037            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23038                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23039            })
23040    }
23041
23042    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23043        if self.mode.is_minimap() {
23044            return;
23045        }
23046        self.addons
23047            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23048    }
23049
23050    pub fn unregister_addon<T: Addon>(&mut self) {
23051        self.addons.remove(&std::any::TypeId::of::<T>());
23052    }
23053
23054    pub fn addon<T: Addon>(&self) -> Option<&T> {
23055        let type_id = std::any::TypeId::of::<T>();
23056        self.addons
23057            .get(&type_id)
23058            .and_then(|item| item.to_any().downcast_ref::<T>())
23059    }
23060
23061    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23062        let type_id = std::any::TypeId::of::<T>();
23063        self.addons
23064            .get_mut(&type_id)
23065            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23066    }
23067
23068    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23069        let text_layout_details = self.text_layout_details(window);
23070        let style = &text_layout_details.editor_style;
23071        let font_id = window.text_system().resolve_font(&style.text.font());
23072        let font_size = style.text.font_size.to_pixels(window.rem_size());
23073        let line_height = style.text.line_height_in_pixels(window.rem_size());
23074        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23075        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23076
23077        CharacterDimensions {
23078            em_width,
23079            em_advance,
23080            line_height,
23081        }
23082    }
23083
23084    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23085        self.load_diff_task.clone()
23086    }
23087
23088    fn read_metadata_from_db(
23089        &mut self,
23090        item_id: u64,
23091        workspace_id: WorkspaceId,
23092        window: &mut Window,
23093        cx: &mut Context<Editor>,
23094    ) {
23095        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23096            && !self.mode.is_minimap()
23097            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
23098        {
23099            let buffer_snapshot = OnceCell::new();
23100
23101            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23102                && !folds.is_empty()
23103            {
23104                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23105                self.fold_ranges(
23106                    folds
23107                        .into_iter()
23108                        .map(|(start, end)| {
23109                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23110                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23111                        })
23112                        .collect(),
23113                    false,
23114                    window,
23115                    cx,
23116                );
23117            }
23118
23119            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23120                && !selections.is_empty()
23121            {
23122                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23123                // skip adding the initial selection to selection history
23124                self.selection_history.mode = SelectionHistoryMode::Skipping;
23125                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23126                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23127                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23128                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23129                    }));
23130                });
23131                self.selection_history.mode = SelectionHistoryMode::Normal;
23132            };
23133        }
23134
23135        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23136    }
23137
23138    fn update_lsp_data(
23139        &mut self,
23140        for_buffer: Option<BufferId>,
23141        window: &mut Window,
23142        cx: &mut Context<'_, Self>,
23143    ) {
23144        self.pull_diagnostics(for_buffer, window, cx);
23145        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23146    }
23147
23148    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23149        if self.ignore_lsp_data() {
23150            return;
23151        }
23152        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23153            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23154        }
23155    }
23156
23157    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23158        if self.ignore_lsp_data() {
23159            return;
23160        }
23161
23162        if !self.registered_buffers.contains_key(&buffer_id)
23163            && let Some(project) = self.project.as_ref()
23164        {
23165            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23166                project.update(cx, |project, cx| {
23167                    self.registered_buffers.insert(
23168                        buffer_id,
23169                        project.register_buffer_with_language_servers(&buffer, cx),
23170                    );
23171                });
23172            } else {
23173                self.registered_buffers.remove(&buffer_id);
23174            }
23175        }
23176    }
23177
23178    fn ignore_lsp_data(&self) -> bool {
23179        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23180        // skip any LSP updates for it.
23181        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23182    }
23183
23184    fn create_style(&self, cx: &App) -> EditorStyle {
23185        let settings = ThemeSettings::get_global(cx);
23186
23187        let mut text_style = match self.mode {
23188            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23189                color: cx.theme().colors().editor_foreground,
23190                font_family: settings.ui_font.family.clone(),
23191                font_features: settings.ui_font.features.clone(),
23192                font_fallbacks: settings.ui_font.fallbacks.clone(),
23193                font_size: rems(0.875).into(),
23194                font_weight: settings.ui_font.weight,
23195                line_height: relative(settings.buffer_line_height.value()),
23196                ..Default::default()
23197            },
23198            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23199                color: cx.theme().colors().editor_foreground,
23200                font_family: settings.buffer_font.family.clone(),
23201                font_features: settings.buffer_font.features.clone(),
23202                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23203                font_size: settings.buffer_font_size(cx).into(),
23204                font_weight: settings.buffer_font.weight,
23205                line_height: relative(settings.buffer_line_height.value()),
23206                ..Default::default()
23207            },
23208        };
23209        if let Some(text_style_refinement) = &self.text_style_refinement {
23210            text_style.refine(text_style_refinement)
23211        }
23212
23213        let background = match self.mode {
23214            EditorMode::SingleLine => cx.theme().system().transparent,
23215            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23216            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23217            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23218        };
23219
23220        EditorStyle {
23221            background,
23222            border: cx.theme().colors().border,
23223            local_player: cx.theme().players().local(),
23224            text: text_style,
23225            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23226            syntax: cx.theme().syntax().clone(),
23227            status: cx.theme().status().clone(),
23228            inlay_hints_style: make_inlay_hints_style(cx),
23229            edit_prediction_styles: make_suggestion_styles(cx),
23230            unnecessary_code_fade: settings.unnecessary_code_fade,
23231            show_underlines: self.diagnostics_enabled(),
23232        }
23233    }
23234}
23235
23236fn edit_for_markdown_paste<'a>(
23237    buffer: &MultiBufferSnapshot,
23238    range: Range<MultiBufferOffset>,
23239    to_insert: &'a str,
23240    url: Option<url::Url>,
23241) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23242    if url.is_none() {
23243        return (range, Cow::Borrowed(to_insert));
23244    };
23245
23246    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23247
23248    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23249        Cow::Borrowed(to_insert)
23250    } else {
23251        Cow::Owned(format!("[{old_text}]({to_insert})"))
23252    };
23253    (range, new_text)
23254}
23255
23256fn process_completion_for_edit(
23257    completion: &Completion,
23258    intent: CompletionIntent,
23259    buffer: &Entity<Buffer>,
23260    cursor_position: &text::Anchor,
23261    cx: &mut Context<Editor>,
23262) -> CompletionEdit {
23263    let buffer = buffer.read(cx);
23264    let buffer_snapshot = buffer.snapshot();
23265    let (snippet, new_text) = if completion.is_snippet() {
23266        let mut snippet_source = completion.new_text.clone();
23267        // Workaround for typescript language server issues so that methods don't expand within
23268        // strings and functions with type expressions. The previous point is used because the query
23269        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23270        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23271        let previous_point = if previous_point.column > 0 {
23272            cursor_position.to_previous_offset(&buffer_snapshot)
23273        } else {
23274            cursor_position.to_offset(&buffer_snapshot)
23275        };
23276        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23277            && scope.prefers_label_for_snippet_in_completion()
23278            && let Some(label) = completion.label()
23279            && matches!(
23280                completion.kind(),
23281                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23282            )
23283        {
23284            snippet_source = label;
23285        }
23286        match Snippet::parse(&snippet_source).log_err() {
23287            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23288            None => (None, completion.new_text.clone()),
23289        }
23290    } else {
23291        (None, completion.new_text.clone())
23292    };
23293
23294    let mut range_to_replace = {
23295        let replace_range = &completion.replace_range;
23296        if let CompletionSource::Lsp {
23297            insert_range: Some(insert_range),
23298            ..
23299        } = &completion.source
23300        {
23301            debug_assert_eq!(
23302                insert_range.start, replace_range.start,
23303                "insert_range and replace_range should start at the same position"
23304            );
23305            debug_assert!(
23306                insert_range
23307                    .start
23308                    .cmp(cursor_position, &buffer_snapshot)
23309                    .is_le(),
23310                "insert_range should start before or at cursor position"
23311            );
23312            debug_assert!(
23313                replace_range
23314                    .start
23315                    .cmp(cursor_position, &buffer_snapshot)
23316                    .is_le(),
23317                "replace_range should start before or at cursor position"
23318            );
23319
23320            let should_replace = match intent {
23321                CompletionIntent::CompleteWithInsert => false,
23322                CompletionIntent::CompleteWithReplace => true,
23323                CompletionIntent::Complete | CompletionIntent::Compose => {
23324                    let insert_mode =
23325                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23326                            .completions
23327                            .lsp_insert_mode;
23328                    match insert_mode {
23329                        LspInsertMode::Insert => false,
23330                        LspInsertMode::Replace => true,
23331                        LspInsertMode::ReplaceSubsequence => {
23332                            let mut text_to_replace = buffer.chars_for_range(
23333                                buffer.anchor_before(replace_range.start)
23334                                    ..buffer.anchor_after(replace_range.end),
23335                            );
23336                            let mut current_needle = text_to_replace.next();
23337                            for haystack_ch in completion.label.text.chars() {
23338                                if let Some(needle_ch) = current_needle
23339                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23340                                {
23341                                    current_needle = text_to_replace.next();
23342                                }
23343                            }
23344                            current_needle.is_none()
23345                        }
23346                        LspInsertMode::ReplaceSuffix => {
23347                            if replace_range
23348                                .end
23349                                .cmp(cursor_position, &buffer_snapshot)
23350                                .is_gt()
23351                            {
23352                                let range_after_cursor = *cursor_position..replace_range.end;
23353                                let text_after_cursor = buffer
23354                                    .text_for_range(
23355                                        buffer.anchor_before(range_after_cursor.start)
23356                                            ..buffer.anchor_after(range_after_cursor.end),
23357                                    )
23358                                    .collect::<String>()
23359                                    .to_ascii_lowercase();
23360                                completion
23361                                    .label
23362                                    .text
23363                                    .to_ascii_lowercase()
23364                                    .ends_with(&text_after_cursor)
23365                            } else {
23366                                true
23367                            }
23368                        }
23369                    }
23370                }
23371            };
23372
23373            if should_replace {
23374                replace_range.clone()
23375            } else {
23376                insert_range.clone()
23377            }
23378        } else {
23379            replace_range.clone()
23380        }
23381    };
23382
23383    if range_to_replace
23384        .end
23385        .cmp(cursor_position, &buffer_snapshot)
23386        .is_lt()
23387    {
23388        range_to_replace.end = *cursor_position;
23389    }
23390
23391    let replace_range = range_to_replace.to_offset(buffer);
23392    CompletionEdit {
23393        new_text,
23394        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23395        snippet,
23396    }
23397}
23398
23399struct CompletionEdit {
23400    new_text: String,
23401    replace_range: Range<BufferOffset>,
23402    snippet: Option<Snippet>,
23403}
23404
23405fn insert_extra_newline_brackets(
23406    buffer: &MultiBufferSnapshot,
23407    range: Range<MultiBufferOffset>,
23408    language: &language::LanguageScope,
23409) -> bool {
23410    let leading_whitespace_len = buffer
23411        .reversed_chars_at(range.start)
23412        .take_while(|c| c.is_whitespace() && *c != '\n')
23413        .map(|c| c.len_utf8())
23414        .sum::<usize>();
23415    let trailing_whitespace_len = buffer
23416        .chars_at(range.end)
23417        .take_while(|c| c.is_whitespace() && *c != '\n')
23418        .map(|c| c.len_utf8())
23419        .sum::<usize>();
23420    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23421
23422    language.brackets().any(|(pair, enabled)| {
23423        let pair_start = pair.start.trim_end();
23424        let pair_end = pair.end.trim_start();
23425
23426        enabled
23427            && pair.newline
23428            && buffer.contains_str_at(range.end, pair_end)
23429            && buffer.contains_str_at(
23430                range.start.saturating_sub_usize(pair_start.len()),
23431                pair_start,
23432            )
23433    })
23434}
23435
23436fn insert_extra_newline_tree_sitter(
23437    buffer: &MultiBufferSnapshot,
23438    range: Range<MultiBufferOffset>,
23439) -> bool {
23440    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23441        [(buffer, range, _)] => (*buffer, range.clone()),
23442        _ => return false,
23443    };
23444    let pair = {
23445        let mut result: Option<BracketMatch<usize>> = None;
23446
23447        for pair in buffer
23448            .all_bracket_ranges(range.start.0..range.end.0)
23449            .filter(move |pair| {
23450                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23451            })
23452        {
23453            let len = pair.close_range.end - pair.open_range.start;
23454
23455            if let Some(existing) = &result {
23456                let existing_len = existing.close_range.end - existing.open_range.start;
23457                if len > existing_len {
23458                    continue;
23459                }
23460            }
23461
23462            result = Some(pair);
23463        }
23464
23465        result
23466    };
23467    let Some(pair) = pair else {
23468        return false;
23469    };
23470    pair.newline_only
23471        && buffer
23472            .chars_for_range(pair.open_range.end..range.start.0)
23473            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23474            .all(|c| c.is_whitespace() && c != '\n')
23475}
23476
23477fn update_uncommitted_diff_for_buffer(
23478    editor: Entity<Editor>,
23479    project: &Entity<Project>,
23480    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23481    buffer: Entity<MultiBuffer>,
23482    cx: &mut App,
23483) -> Task<()> {
23484    let mut tasks = Vec::new();
23485    project.update(cx, |project, cx| {
23486        for buffer in buffers {
23487            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23488                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23489            }
23490        }
23491    });
23492    cx.spawn(async move |cx| {
23493        let diffs = future::join_all(tasks).await;
23494        if editor
23495            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23496            .unwrap_or(false)
23497        {
23498            return;
23499        }
23500
23501        buffer
23502            .update(cx, |buffer, cx| {
23503                for diff in diffs.into_iter().flatten() {
23504                    buffer.add_diff(diff, cx);
23505                }
23506            })
23507            .ok();
23508    })
23509}
23510
23511fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23512    let tab_size = tab_size.get() as usize;
23513    let mut width = offset;
23514
23515    for ch in text.chars() {
23516        width += if ch == '\t' {
23517            tab_size - (width % tab_size)
23518        } else {
23519            1
23520        };
23521    }
23522
23523    width - offset
23524}
23525
23526#[cfg(test)]
23527mod tests {
23528    use super::*;
23529
23530    #[test]
23531    fn test_string_size_with_expanded_tabs() {
23532        let nz = |val| NonZeroU32::new(val).unwrap();
23533        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23534        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23535        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23536        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23537        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23538        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23539        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23540        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23541    }
23542}
23543
23544/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23545struct WordBreakingTokenizer<'a> {
23546    input: &'a str,
23547}
23548
23549impl<'a> WordBreakingTokenizer<'a> {
23550    fn new(input: &'a str) -> Self {
23551        Self { input }
23552    }
23553}
23554
23555fn is_char_ideographic(ch: char) -> bool {
23556    use unicode_script::Script::*;
23557    use unicode_script::UnicodeScript;
23558    matches!(ch.script(), Han | Tangut | Yi)
23559}
23560
23561fn is_grapheme_ideographic(text: &str) -> bool {
23562    text.chars().any(is_char_ideographic)
23563}
23564
23565fn is_grapheme_whitespace(text: &str) -> bool {
23566    text.chars().any(|x| x.is_whitespace())
23567}
23568
23569fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23570    text.chars()
23571        .next()
23572        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23573}
23574
23575#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23576enum WordBreakToken<'a> {
23577    Word { token: &'a str, grapheme_len: usize },
23578    InlineWhitespace { token: &'a str, grapheme_len: usize },
23579    Newline,
23580}
23581
23582impl<'a> Iterator for WordBreakingTokenizer<'a> {
23583    /// Yields a span, the count of graphemes in the token, and whether it was
23584    /// whitespace. Note that it also breaks at word boundaries.
23585    type Item = WordBreakToken<'a>;
23586
23587    fn next(&mut self) -> Option<Self::Item> {
23588        use unicode_segmentation::UnicodeSegmentation;
23589        if self.input.is_empty() {
23590            return None;
23591        }
23592
23593        let mut iter = self.input.graphemes(true).peekable();
23594        let mut offset = 0;
23595        let mut grapheme_len = 0;
23596        if let Some(first_grapheme) = iter.next() {
23597            let is_newline = first_grapheme == "\n";
23598            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23599            offset += first_grapheme.len();
23600            grapheme_len += 1;
23601            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23602                if let Some(grapheme) = iter.peek().copied()
23603                    && should_stay_with_preceding_ideograph(grapheme)
23604                {
23605                    offset += grapheme.len();
23606                    grapheme_len += 1;
23607                }
23608            } else {
23609                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23610                let mut next_word_bound = words.peek().copied();
23611                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23612                    next_word_bound = words.next();
23613                }
23614                while let Some(grapheme) = iter.peek().copied() {
23615                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23616                        break;
23617                    };
23618                    if is_grapheme_whitespace(grapheme) != is_whitespace
23619                        || (grapheme == "\n") != is_newline
23620                    {
23621                        break;
23622                    };
23623                    offset += grapheme.len();
23624                    grapheme_len += 1;
23625                    iter.next();
23626                }
23627            }
23628            let token = &self.input[..offset];
23629            self.input = &self.input[offset..];
23630            if token == "\n" {
23631                Some(WordBreakToken::Newline)
23632            } else if is_whitespace {
23633                Some(WordBreakToken::InlineWhitespace {
23634                    token,
23635                    grapheme_len,
23636                })
23637            } else {
23638                Some(WordBreakToken::Word {
23639                    token,
23640                    grapheme_len,
23641                })
23642            }
23643        } else {
23644            None
23645        }
23646    }
23647}
23648
23649#[test]
23650fn test_word_breaking_tokenizer() {
23651    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23652        ("", &[]),
23653        ("  ", &[whitespace("  ", 2)]),
23654        ("Ʒ", &[word("Ʒ", 1)]),
23655        ("Ǽ", &[word("Ǽ", 1)]),
23656        ("", &[word("", 1)]),
23657        ("⋑⋑", &[word("⋑⋑", 2)]),
23658        (
23659            "原理,进而",
23660            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23661        ),
23662        (
23663            "hello world",
23664            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23665        ),
23666        (
23667            "hello, world",
23668            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23669        ),
23670        (
23671            "  hello world",
23672            &[
23673                whitespace("  ", 2),
23674                word("hello", 5),
23675                whitespace(" ", 1),
23676                word("world", 5),
23677            ],
23678        ),
23679        (
23680            "这是什么 \n 钢笔",
23681            &[
23682                word("", 1),
23683                word("", 1),
23684                word("", 1),
23685                word("", 1),
23686                whitespace(" ", 1),
23687                newline(),
23688                whitespace(" ", 1),
23689                word("", 1),
23690                word("", 1),
23691            ],
23692        ),
23693        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23694    ];
23695
23696    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23697        WordBreakToken::Word {
23698            token,
23699            grapheme_len,
23700        }
23701    }
23702
23703    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23704        WordBreakToken::InlineWhitespace {
23705            token,
23706            grapheme_len,
23707        }
23708    }
23709
23710    fn newline() -> WordBreakToken<'static> {
23711        WordBreakToken::Newline
23712    }
23713
23714    for (input, result) in tests {
23715        assert_eq!(
23716            WordBreakingTokenizer::new(input)
23717                .collect::<Vec<_>>()
23718                .as_slice(),
23719            *result,
23720        );
23721    }
23722}
23723
23724fn wrap_with_prefix(
23725    first_line_prefix: String,
23726    subsequent_lines_prefix: String,
23727    unwrapped_text: String,
23728    wrap_column: usize,
23729    tab_size: NonZeroU32,
23730    preserve_existing_whitespace: bool,
23731) -> String {
23732    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23733    let subsequent_lines_prefix_len =
23734        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23735    let mut wrapped_text = String::new();
23736    let mut current_line = first_line_prefix;
23737    let mut is_first_line = true;
23738
23739    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23740    let mut current_line_len = first_line_prefix_len;
23741    let mut in_whitespace = false;
23742    for token in tokenizer {
23743        let have_preceding_whitespace = in_whitespace;
23744        match token {
23745            WordBreakToken::Word {
23746                token,
23747                grapheme_len,
23748            } => {
23749                in_whitespace = false;
23750                let current_prefix_len = if is_first_line {
23751                    first_line_prefix_len
23752                } else {
23753                    subsequent_lines_prefix_len
23754                };
23755                if current_line_len + grapheme_len > wrap_column
23756                    && current_line_len != current_prefix_len
23757                {
23758                    wrapped_text.push_str(current_line.trim_end());
23759                    wrapped_text.push('\n');
23760                    is_first_line = false;
23761                    current_line = subsequent_lines_prefix.clone();
23762                    current_line_len = subsequent_lines_prefix_len;
23763                }
23764                current_line.push_str(token);
23765                current_line_len += grapheme_len;
23766            }
23767            WordBreakToken::InlineWhitespace {
23768                mut token,
23769                mut grapheme_len,
23770            } => {
23771                in_whitespace = true;
23772                if have_preceding_whitespace && !preserve_existing_whitespace {
23773                    continue;
23774                }
23775                if !preserve_existing_whitespace {
23776                    // Keep a single whitespace grapheme as-is
23777                    if let Some(first) =
23778                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23779                    {
23780                        token = first;
23781                    } else {
23782                        token = " ";
23783                    }
23784                    grapheme_len = 1;
23785                }
23786                let current_prefix_len = if is_first_line {
23787                    first_line_prefix_len
23788                } else {
23789                    subsequent_lines_prefix_len
23790                };
23791                if current_line_len + grapheme_len > wrap_column {
23792                    wrapped_text.push_str(current_line.trim_end());
23793                    wrapped_text.push('\n');
23794                    is_first_line = false;
23795                    current_line = subsequent_lines_prefix.clone();
23796                    current_line_len = subsequent_lines_prefix_len;
23797                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23798                    current_line.push_str(token);
23799                    current_line_len += grapheme_len;
23800                }
23801            }
23802            WordBreakToken::Newline => {
23803                in_whitespace = true;
23804                let current_prefix_len = if is_first_line {
23805                    first_line_prefix_len
23806                } else {
23807                    subsequent_lines_prefix_len
23808                };
23809                if preserve_existing_whitespace {
23810                    wrapped_text.push_str(current_line.trim_end());
23811                    wrapped_text.push('\n');
23812                    is_first_line = false;
23813                    current_line = subsequent_lines_prefix.clone();
23814                    current_line_len = subsequent_lines_prefix_len;
23815                } else if have_preceding_whitespace {
23816                    continue;
23817                } else if current_line_len + 1 > wrap_column
23818                    && current_line_len != current_prefix_len
23819                {
23820                    wrapped_text.push_str(current_line.trim_end());
23821                    wrapped_text.push('\n');
23822                    is_first_line = false;
23823                    current_line = subsequent_lines_prefix.clone();
23824                    current_line_len = subsequent_lines_prefix_len;
23825                } else if current_line_len != current_prefix_len {
23826                    current_line.push(' ');
23827                    current_line_len += 1;
23828                }
23829            }
23830        }
23831    }
23832
23833    if !current_line.is_empty() {
23834        wrapped_text.push_str(&current_line);
23835    }
23836    wrapped_text
23837}
23838
23839#[test]
23840fn test_wrap_with_prefix() {
23841    assert_eq!(
23842        wrap_with_prefix(
23843            "# ".to_string(),
23844            "# ".to_string(),
23845            "abcdefg".to_string(),
23846            4,
23847            NonZeroU32::new(4).unwrap(),
23848            false,
23849        ),
23850        "# abcdefg"
23851    );
23852    assert_eq!(
23853        wrap_with_prefix(
23854            "".to_string(),
23855            "".to_string(),
23856            "\thello world".to_string(),
23857            8,
23858            NonZeroU32::new(4).unwrap(),
23859            false,
23860        ),
23861        "hello\nworld"
23862    );
23863    assert_eq!(
23864        wrap_with_prefix(
23865            "// ".to_string(),
23866            "// ".to_string(),
23867            "xx \nyy zz aa bb cc".to_string(),
23868            12,
23869            NonZeroU32::new(4).unwrap(),
23870            false,
23871        ),
23872        "// xx yy zz\n// aa bb cc"
23873    );
23874    assert_eq!(
23875        wrap_with_prefix(
23876            String::new(),
23877            String::new(),
23878            "这是什么 \n 钢笔".to_string(),
23879            3,
23880            NonZeroU32::new(4).unwrap(),
23881            false,
23882        ),
23883        "这是什\n么 钢\n"
23884    );
23885    assert_eq!(
23886        wrap_with_prefix(
23887            String::new(),
23888            String::new(),
23889            format!("foo{}bar", '\u{2009}'), // thin space
23890            80,
23891            NonZeroU32::new(4).unwrap(),
23892            false,
23893        ),
23894        format!("foo{}bar", '\u{2009}')
23895    );
23896}
23897
23898pub trait CollaborationHub {
23899    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23900    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23901    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23902}
23903
23904impl CollaborationHub for Entity<Project> {
23905    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23906        self.read(cx).collaborators()
23907    }
23908
23909    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23910        self.read(cx).user_store().read(cx).participant_indices()
23911    }
23912
23913    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23914        let this = self.read(cx);
23915        let user_ids = this.collaborators().values().map(|c| c.user_id);
23916        this.user_store().read(cx).participant_names(user_ids, cx)
23917    }
23918}
23919
23920pub trait SemanticsProvider {
23921    fn hover(
23922        &self,
23923        buffer: &Entity<Buffer>,
23924        position: text::Anchor,
23925        cx: &mut App,
23926    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23927
23928    fn inline_values(
23929        &self,
23930        buffer_handle: Entity<Buffer>,
23931        range: Range<text::Anchor>,
23932        cx: &mut App,
23933    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23934
23935    fn applicable_inlay_chunks(
23936        &self,
23937        buffer: &Entity<Buffer>,
23938        ranges: &[Range<text::Anchor>],
23939        cx: &mut App,
23940    ) -> Vec<Range<BufferRow>>;
23941
23942    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23943
23944    fn inlay_hints(
23945        &self,
23946        invalidate: InvalidationStrategy,
23947        buffer: Entity<Buffer>,
23948        ranges: Vec<Range<text::Anchor>>,
23949        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23950        cx: &mut App,
23951    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23952
23953    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23954
23955    fn document_highlights(
23956        &self,
23957        buffer: &Entity<Buffer>,
23958        position: text::Anchor,
23959        cx: &mut App,
23960    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23961
23962    fn definitions(
23963        &self,
23964        buffer: &Entity<Buffer>,
23965        position: text::Anchor,
23966        kind: GotoDefinitionKind,
23967        cx: &mut App,
23968    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23969
23970    fn range_for_rename(
23971        &self,
23972        buffer: &Entity<Buffer>,
23973        position: text::Anchor,
23974        cx: &mut App,
23975    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23976
23977    fn perform_rename(
23978        &self,
23979        buffer: &Entity<Buffer>,
23980        position: text::Anchor,
23981        new_name: String,
23982        cx: &mut App,
23983    ) -> Option<Task<Result<ProjectTransaction>>>;
23984}
23985
23986pub trait CompletionProvider {
23987    fn completions(
23988        &self,
23989        excerpt_id: ExcerptId,
23990        buffer: &Entity<Buffer>,
23991        buffer_position: text::Anchor,
23992        trigger: CompletionContext,
23993        window: &mut Window,
23994        cx: &mut Context<Editor>,
23995    ) -> Task<Result<Vec<CompletionResponse>>>;
23996
23997    fn resolve_completions(
23998        &self,
23999        _buffer: Entity<Buffer>,
24000        _completion_indices: Vec<usize>,
24001        _completions: Rc<RefCell<Box<[Completion]>>>,
24002        _cx: &mut Context<Editor>,
24003    ) -> Task<Result<bool>> {
24004        Task::ready(Ok(false))
24005    }
24006
24007    fn apply_additional_edits_for_completion(
24008        &self,
24009        _buffer: Entity<Buffer>,
24010        _completions: Rc<RefCell<Box<[Completion]>>>,
24011        _completion_index: usize,
24012        _push_to_history: bool,
24013        _cx: &mut Context<Editor>,
24014    ) -> Task<Result<Option<language::Transaction>>> {
24015        Task::ready(Ok(None))
24016    }
24017
24018    fn is_completion_trigger(
24019        &self,
24020        buffer: &Entity<Buffer>,
24021        position: language::Anchor,
24022        text: &str,
24023        trigger_in_words: bool,
24024        cx: &mut Context<Editor>,
24025    ) -> bool;
24026
24027    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24028
24029    fn sort_completions(&self) -> bool {
24030        true
24031    }
24032
24033    fn filter_completions(&self) -> bool {
24034        true
24035    }
24036
24037    fn show_snippets(&self) -> bool {
24038        false
24039    }
24040}
24041
24042pub trait CodeActionProvider {
24043    fn id(&self) -> Arc<str>;
24044
24045    fn code_actions(
24046        &self,
24047        buffer: &Entity<Buffer>,
24048        range: Range<text::Anchor>,
24049        window: &mut Window,
24050        cx: &mut App,
24051    ) -> Task<Result<Vec<CodeAction>>>;
24052
24053    fn apply_code_action(
24054        &self,
24055        buffer_handle: Entity<Buffer>,
24056        action: CodeAction,
24057        excerpt_id: ExcerptId,
24058        push_to_history: bool,
24059        window: &mut Window,
24060        cx: &mut App,
24061    ) -> Task<Result<ProjectTransaction>>;
24062}
24063
24064impl CodeActionProvider for Entity<Project> {
24065    fn id(&self) -> Arc<str> {
24066        "project".into()
24067    }
24068
24069    fn code_actions(
24070        &self,
24071        buffer: &Entity<Buffer>,
24072        range: Range<text::Anchor>,
24073        _window: &mut Window,
24074        cx: &mut App,
24075    ) -> Task<Result<Vec<CodeAction>>> {
24076        self.update(cx, |project, cx| {
24077            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24078            let code_actions = project.code_actions(buffer, range, None, cx);
24079            cx.background_spawn(async move {
24080                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24081                Ok(code_lens_actions
24082                    .context("code lens fetch")?
24083                    .into_iter()
24084                    .flatten()
24085                    .chain(
24086                        code_actions
24087                            .context("code action fetch")?
24088                            .into_iter()
24089                            .flatten(),
24090                    )
24091                    .collect())
24092            })
24093        })
24094    }
24095
24096    fn apply_code_action(
24097        &self,
24098        buffer_handle: Entity<Buffer>,
24099        action: CodeAction,
24100        _excerpt_id: ExcerptId,
24101        push_to_history: bool,
24102        _window: &mut Window,
24103        cx: &mut App,
24104    ) -> Task<Result<ProjectTransaction>> {
24105        self.update(cx, |project, cx| {
24106            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24107        })
24108    }
24109}
24110
24111fn snippet_completions(
24112    project: &Project,
24113    buffer: &Entity<Buffer>,
24114    buffer_anchor: text::Anchor,
24115    classifier: CharClassifier,
24116    cx: &mut App,
24117) -> Task<Result<CompletionResponse>> {
24118    let languages = buffer.read(cx).languages_at(buffer_anchor);
24119    let snippet_store = project.snippets().read(cx);
24120
24121    let scopes: Vec<_> = languages
24122        .iter()
24123        .filter_map(|language| {
24124            let language_name = language.lsp_id();
24125            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24126
24127            if snippets.is_empty() {
24128                None
24129            } else {
24130                Some((language.default_scope(), snippets))
24131            }
24132        })
24133        .collect();
24134
24135    if scopes.is_empty() {
24136        return Task::ready(Ok(CompletionResponse {
24137            completions: vec![],
24138            display_options: CompletionDisplayOptions::default(),
24139            is_incomplete: false,
24140        }));
24141    }
24142
24143    let snapshot = buffer.read(cx).text_snapshot();
24144    let executor = cx.background_executor().clone();
24145
24146    cx.background_spawn(async move {
24147        let is_word_char = |c| classifier.is_word(c);
24148
24149        let mut is_incomplete = false;
24150        let mut completions: Vec<Completion> = Vec::new();
24151
24152        const MAX_PREFIX_LEN: usize = 128;
24153        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24154        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24155        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24156
24157        let max_buffer_window: String = snapshot
24158            .text_for_range(window_start..buffer_offset)
24159            .collect();
24160
24161        if max_buffer_window.is_empty() {
24162            return Ok(CompletionResponse {
24163                completions: vec![],
24164                display_options: CompletionDisplayOptions::default(),
24165                is_incomplete: true,
24166            });
24167        }
24168
24169        for (_scope, snippets) in scopes.into_iter() {
24170            // Sort snippets by word count to match longer snippet prefixes first.
24171            let mut sorted_snippet_candidates = snippets
24172                .iter()
24173                .enumerate()
24174                .flat_map(|(snippet_ix, snippet)| {
24175                    snippet
24176                        .prefix
24177                        .iter()
24178                        .enumerate()
24179                        .map(move |(prefix_ix, prefix)| {
24180                            let word_count =
24181                                snippet_candidate_suffixes(prefix, is_word_char).count();
24182                            ((snippet_ix, prefix_ix), prefix, word_count)
24183                        })
24184                })
24185                .collect_vec();
24186            sorted_snippet_candidates
24187                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24188
24189            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24190
24191            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24192                .take(
24193                    sorted_snippet_candidates
24194                        .first()
24195                        .map(|(_, _, word_count)| *word_count)
24196                        .unwrap_or_default(),
24197                )
24198                .collect_vec();
24199
24200            const MAX_RESULTS: usize = 100;
24201            // Each match also remembers how many characters from the buffer it consumed
24202            let mut matches: Vec<(StringMatch, usize)> = vec![];
24203
24204            let mut snippet_list_cutoff_index = 0;
24205            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24206                let word_count = buffer_index + 1;
24207                // Increase `snippet_list_cutoff_index` until we have all of the
24208                // snippets with sufficiently many words.
24209                while sorted_snippet_candidates
24210                    .get(snippet_list_cutoff_index)
24211                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24212                        *snippet_word_count >= word_count
24213                    })
24214                {
24215                    snippet_list_cutoff_index += 1;
24216                }
24217
24218                // Take only the candidates with at least `word_count` many words
24219                let snippet_candidates_at_word_len =
24220                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24221
24222                let candidates = snippet_candidates_at_word_len
24223                    .iter()
24224                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24225                    .enumerate() // index in `sorted_snippet_candidates`
24226                    // First char must match
24227                    .filter(|(_ix, prefix)| {
24228                        itertools::equal(
24229                            prefix
24230                                .chars()
24231                                .next()
24232                                .into_iter()
24233                                .flat_map(|c| c.to_lowercase()),
24234                            buffer_window
24235                                .chars()
24236                                .next()
24237                                .into_iter()
24238                                .flat_map(|c| c.to_lowercase()),
24239                        )
24240                    })
24241                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24242                    .collect::<Vec<StringMatchCandidate>>();
24243
24244                matches.extend(
24245                    fuzzy::match_strings(
24246                        &candidates,
24247                        &buffer_window,
24248                        buffer_window.chars().any(|c| c.is_uppercase()),
24249                        true,
24250                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24251                        &Default::default(),
24252                        executor.clone(),
24253                    )
24254                    .await
24255                    .into_iter()
24256                    .map(|string_match| (string_match, buffer_window.len())),
24257                );
24258
24259                if matches.len() >= MAX_RESULTS {
24260                    break;
24261                }
24262            }
24263
24264            let to_lsp = |point: &text::Anchor| {
24265                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24266                point_to_lsp(end)
24267            };
24268            let lsp_end = to_lsp(&buffer_anchor);
24269
24270            if matches.len() >= MAX_RESULTS {
24271                is_incomplete = true;
24272            }
24273
24274            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24275                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24276                    sorted_snippet_candidates[string_match.candidate_id];
24277                let snippet = &snippets[snippet_index];
24278                let start = buffer_offset - buffer_window_len;
24279                let start = snapshot.anchor_before(start);
24280                let range = start..buffer_anchor;
24281                let lsp_start = to_lsp(&start);
24282                let lsp_range = lsp::Range {
24283                    start: lsp_start,
24284                    end: lsp_end,
24285                };
24286                Completion {
24287                    replace_range: range,
24288                    new_text: snippet.body.clone(),
24289                    source: CompletionSource::Lsp {
24290                        insert_range: None,
24291                        server_id: LanguageServerId(usize::MAX),
24292                        resolved: true,
24293                        lsp_completion: Box::new(lsp::CompletionItem {
24294                            label: snippet.prefix.first().unwrap().clone(),
24295                            kind: Some(CompletionItemKind::SNIPPET),
24296                            label_details: snippet.description.as_ref().map(|description| {
24297                                lsp::CompletionItemLabelDetails {
24298                                    detail: Some(description.clone()),
24299                                    description: None,
24300                                }
24301                            }),
24302                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24303                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24304                                lsp::InsertReplaceEdit {
24305                                    new_text: snippet.body.clone(),
24306                                    insert: lsp_range,
24307                                    replace: lsp_range,
24308                                },
24309                            )),
24310                            filter_text: Some(snippet.body.clone()),
24311                            sort_text: Some(char::MAX.to_string()),
24312                            ..lsp::CompletionItem::default()
24313                        }),
24314                        lsp_defaults: None,
24315                    },
24316                    label: CodeLabel {
24317                        text: matching_prefix.clone(),
24318                        runs: Vec::new(),
24319                        filter_range: 0..matching_prefix.len(),
24320                    },
24321                    icon_path: None,
24322                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24323                        single_line: snippet.name.clone().into(),
24324                        plain_text: snippet
24325                            .description
24326                            .clone()
24327                            .map(|description| description.into()),
24328                    }),
24329                    insert_text_mode: None,
24330                    confirm: None,
24331                    match_start: Some(start),
24332                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24333                }
24334            }));
24335        }
24336
24337        Ok(CompletionResponse {
24338            completions,
24339            display_options: CompletionDisplayOptions::default(),
24340            is_incomplete,
24341        })
24342    })
24343}
24344
24345impl CompletionProvider for Entity<Project> {
24346    fn completions(
24347        &self,
24348        _excerpt_id: ExcerptId,
24349        buffer: &Entity<Buffer>,
24350        buffer_position: text::Anchor,
24351        options: CompletionContext,
24352        _window: &mut Window,
24353        cx: &mut Context<Editor>,
24354    ) -> Task<Result<Vec<CompletionResponse>>> {
24355        self.update(cx, |project, cx| {
24356            let task = project.completions(buffer, buffer_position, options, cx);
24357            cx.background_spawn(task)
24358        })
24359    }
24360
24361    fn resolve_completions(
24362        &self,
24363        buffer: Entity<Buffer>,
24364        completion_indices: Vec<usize>,
24365        completions: Rc<RefCell<Box<[Completion]>>>,
24366        cx: &mut Context<Editor>,
24367    ) -> Task<Result<bool>> {
24368        self.update(cx, |project, cx| {
24369            project.lsp_store().update(cx, |lsp_store, cx| {
24370                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24371            })
24372        })
24373    }
24374
24375    fn apply_additional_edits_for_completion(
24376        &self,
24377        buffer: Entity<Buffer>,
24378        completions: Rc<RefCell<Box<[Completion]>>>,
24379        completion_index: usize,
24380        push_to_history: bool,
24381        cx: &mut Context<Editor>,
24382    ) -> Task<Result<Option<language::Transaction>>> {
24383        self.update(cx, |project, cx| {
24384            project.lsp_store().update(cx, |lsp_store, cx| {
24385                lsp_store.apply_additional_edits_for_completion(
24386                    buffer,
24387                    completions,
24388                    completion_index,
24389                    push_to_history,
24390                    cx,
24391                )
24392            })
24393        })
24394    }
24395
24396    fn is_completion_trigger(
24397        &self,
24398        buffer: &Entity<Buffer>,
24399        position: language::Anchor,
24400        text: &str,
24401        trigger_in_words: bool,
24402        cx: &mut Context<Editor>,
24403    ) -> bool {
24404        let mut chars = text.chars();
24405        let char = if let Some(char) = chars.next() {
24406            char
24407        } else {
24408            return false;
24409        };
24410        if chars.next().is_some() {
24411            return false;
24412        }
24413
24414        let buffer = buffer.read(cx);
24415        let snapshot = buffer.snapshot();
24416        let classifier = snapshot
24417            .char_classifier_at(position)
24418            .scope_context(Some(CharScopeContext::Completion));
24419        if trigger_in_words && classifier.is_word(char) {
24420            return true;
24421        }
24422
24423        buffer.completion_triggers().contains(text)
24424    }
24425
24426    fn show_snippets(&self) -> bool {
24427        true
24428    }
24429}
24430
24431impl SemanticsProvider for Entity<Project> {
24432    fn hover(
24433        &self,
24434        buffer: &Entity<Buffer>,
24435        position: text::Anchor,
24436        cx: &mut App,
24437    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24438        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24439    }
24440
24441    fn document_highlights(
24442        &self,
24443        buffer: &Entity<Buffer>,
24444        position: text::Anchor,
24445        cx: &mut App,
24446    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24447        Some(self.update(cx, |project, cx| {
24448            project.document_highlights(buffer, position, cx)
24449        }))
24450    }
24451
24452    fn definitions(
24453        &self,
24454        buffer: &Entity<Buffer>,
24455        position: text::Anchor,
24456        kind: GotoDefinitionKind,
24457        cx: &mut App,
24458    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24459        Some(self.update(cx, |project, cx| match kind {
24460            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24461            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24462            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24463            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24464        }))
24465    }
24466
24467    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24468        self.update(cx, |project, cx| {
24469            if project
24470                .active_debug_session(cx)
24471                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24472            {
24473                return true;
24474            }
24475
24476            buffer.update(cx, |buffer, cx| {
24477                project.any_language_server_supports_inlay_hints(buffer, cx)
24478            })
24479        })
24480    }
24481
24482    fn inline_values(
24483        &self,
24484        buffer_handle: Entity<Buffer>,
24485        range: Range<text::Anchor>,
24486        cx: &mut App,
24487    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24488        self.update(cx, |project, cx| {
24489            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24490
24491            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24492        })
24493    }
24494
24495    fn applicable_inlay_chunks(
24496        &self,
24497        buffer: &Entity<Buffer>,
24498        ranges: &[Range<text::Anchor>],
24499        cx: &mut App,
24500    ) -> Vec<Range<BufferRow>> {
24501        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24502            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24503        })
24504    }
24505
24506    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24507        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24508            lsp_store.invalidate_inlay_hints(for_buffers)
24509        });
24510    }
24511
24512    fn inlay_hints(
24513        &self,
24514        invalidate: InvalidationStrategy,
24515        buffer: Entity<Buffer>,
24516        ranges: Vec<Range<text::Anchor>>,
24517        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24518        cx: &mut App,
24519    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24520        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24521            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24522        }))
24523    }
24524
24525    fn range_for_rename(
24526        &self,
24527        buffer: &Entity<Buffer>,
24528        position: text::Anchor,
24529        cx: &mut App,
24530    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24531        Some(self.update(cx, |project, cx| {
24532            let buffer = buffer.clone();
24533            let task = project.prepare_rename(buffer.clone(), position, cx);
24534            cx.spawn(async move |_, cx| {
24535                Ok(match task.await? {
24536                    PrepareRenameResponse::Success(range) => Some(range),
24537                    PrepareRenameResponse::InvalidPosition => None,
24538                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24539                        // Fallback on using TreeSitter info to determine identifier range
24540                        buffer.read_with(cx, |buffer, _| {
24541                            let snapshot = buffer.snapshot();
24542                            let (range, kind) = snapshot.surrounding_word(position, None);
24543                            if kind != Some(CharKind::Word) {
24544                                return None;
24545                            }
24546                            Some(
24547                                snapshot.anchor_before(range.start)
24548                                    ..snapshot.anchor_after(range.end),
24549                            )
24550                        })?
24551                    }
24552                })
24553            })
24554        }))
24555    }
24556
24557    fn perform_rename(
24558        &self,
24559        buffer: &Entity<Buffer>,
24560        position: text::Anchor,
24561        new_name: String,
24562        cx: &mut App,
24563    ) -> Option<Task<Result<ProjectTransaction>>> {
24564        Some(self.update(cx, |project, cx| {
24565            project.perform_rename(buffer.clone(), position, new_name, cx)
24566        }))
24567    }
24568}
24569
24570fn consume_contiguous_rows(
24571    contiguous_row_selections: &mut Vec<Selection<Point>>,
24572    selection: &Selection<Point>,
24573    display_map: &DisplaySnapshot,
24574    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24575) -> (MultiBufferRow, MultiBufferRow) {
24576    contiguous_row_selections.push(selection.clone());
24577    let start_row = starting_row(selection, display_map);
24578    let mut end_row = ending_row(selection, display_map);
24579
24580    while let Some(next_selection) = selections.peek() {
24581        if next_selection.start.row <= end_row.0 {
24582            end_row = ending_row(next_selection, display_map);
24583            contiguous_row_selections.push(selections.next().unwrap().clone());
24584        } else {
24585            break;
24586        }
24587    }
24588    (start_row, end_row)
24589}
24590
24591fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24592    if selection.start.column > 0 {
24593        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24594    } else {
24595        MultiBufferRow(selection.start.row)
24596    }
24597}
24598
24599fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24600    if next_selection.end.column > 0 || next_selection.is_empty() {
24601        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24602    } else {
24603        MultiBufferRow(next_selection.end.row)
24604    }
24605}
24606
24607impl EditorSnapshot {
24608    pub fn remote_selections_in_range<'a>(
24609        &'a self,
24610        range: &'a Range<Anchor>,
24611        collaboration_hub: &dyn CollaborationHub,
24612        cx: &'a App,
24613    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24614        let participant_names = collaboration_hub.user_names(cx);
24615        let participant_indices = collaboration_hub.user_participant_indices(cx);
24616        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24617        let collaborators_by_replica_id = collaborators_by_peer_id
24618            .values()
24619            .map(|collaborator| (collaborator.replica_id, collaborator))
24620            .collect::<HashMap<_, _>>();
24621        self.buffer_snapshot()
24622            .selections_in_range(range, false)
24623            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24624                if replica_id == ReplicaId::AGENT {
24625                    Some(RemoteSelection {
24626                        replica_id,
24627                        selection,
24628                        cursor_shape,
24629                        line_mode,
24630                        collaborator_id: CollaboratorId::Agent,
24631                        user_name: Some("Agent".into()),
24632                        color: cx.theme().players().agent(),
24633                    })
24634                } else {
24635                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24636                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24637                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24638                    Some(RemoteSelection {
24639                        replica_id,
24640                        selection,
24641                        cursor_shape,
24642                        line_mode,
24643                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24644                        user_name,
24645                        color: if let Some(index) = participant_index {
24646                            cx.theme().players().color_for_participant(index.0)
24647                        } else {
24648                            cx.theme().players().absent()
24649                        },
24650                    })
24651                }
24652            })
24653    }
24654
24655    pub fn hunks_for_ranges(
24656        &self,
24657        ranges: impl IntoIterator<Item = Range<Point>>,
24658    ) -> Vec<MultiBufferDiffHunk> {
24659        let mut hunks = Vec::new();
24660        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24661            HashMap::default();
24662        for query_range in ranges {
24663            let query_rows =
24664                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24665            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24666                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24667            ) {
24668                // Include deleted hunks that are adjacent to the query range, because
24669                // otherwise they would be missed.
24670                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24671                if hunk.status().is_deleted() {
24672                    intersects_range |= hunk.row_range.start == query_rows.end;
24673                    intersects_range |= hunk.row_range.end == query_rows.start;
24674                }
24675                if intersects_range {
24676                    if !processed_buffer_rows
24677                        .entry(hunk.buffer_id)
24678                        .or_default()
24679                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24680                    {
24681                        continue;
24682                    }
24683                    hunks.push(hunk);
24684                }
24685            }
24686        }
24687
24688        hunks
24689    }
24690
24691    fn display_diff_hunks_for_rows<'a>(
24692        &'a self,
24693        display_rows: Range<DisplayRow>,
24694        folded_buffers: &'a HashSet<BufferId>,
24695    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24696        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24697        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24698
24699        self.buffer_snapshot()
24700            .diff_hunks_in_range(buffer_start..buffer_end)
24701            .filter_map(|hunk| {
24702                if folded_buffers.contains(&hunk.buffer_id) {
24703                    return None;
24704                }
24705
24706                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24707                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24708
24709                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24710                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24711
24712                let display_hunk = if hunk_display_start.column() != 0 {
24713                    DisplayDiffHunk::Folded {
24714                        display_row: hunk_display_start.row(),
24715                    }
24716                } else {
24717                    let mut end_row = hunk_display_end.row();
24718                    if hunk_display_end.column() > 0 {
24719                        end_row.0 += 1;
24720                    }
24721                    let is_created_file = hunk.is_created_file();
24722
24723                    DisplayDiffHunk::Unfolded {
24724                        status: hunk.status(),
24725                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24726                            ..hunk.diff_base_byte_range.end.0,
24727                        word_diffs: hunk.word_diffs,
24728                        display_row_range: hunk_display_start.row()..end_row,
24729                        multi_buffer_range: Anchor::range_in_buffer(
24730                            hunk.excerpt_id,
24731                            hunk.buffer_range,
24732                        ),
24733                        is_created_file,
24734                    }
24735                };
24736
24737                Some(display_hunk)
24738            })
24739    }
24740
24741    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24742        self.display_snapshot
24743            .buffer_snapshot()
24744            .language_at(position)
24745    }
24746
24747    pub fn is_focused(&self) -> bool {
24748        self.is_focused
24749    }
24750
24751    pub fn placeholder_text(&self) -> Option<String> {
24752        self.placeholder_display_snapshot
24753            .as_ref()
24754            .map(|display_map| display_map.text())
24755    }
24756
24757    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24758        self.scroll_anchor.scroll_position(&self.display_snapshot)
24759    }
24760
24761    pub fn gutter_dimensions(
24762        &self,
24763        font_id: FontId,
24764        font_size: Pixels,
24765        style: &EditorStyle,
24766        window: &mut Window,
24767        cx: &App,
24768    ) -> GutterDimensions {
24769        if self.show_gutter
24770            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
24771            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
24772        {
24773            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24774                matches!(
24775                    ProjectSettings::get_global(cx).git.git_gutter,
24776                    GitGutterSetting::TrackedFiles
24777                )
24778            });
24779            let gutter_settings = EditorSettings::get_global(cx).gutter;
24780            let show_line_numbers = self
24781                .show_line_numbers
24782                .unwrap_or(gutter_settings.line_numbers);
24783            let line_gutter_width = if show_line_numbers {
24784                // Avoid flicker-like gutter resizes when the line number gains another digit by
24785                // only resizing the gutter on files with > 10**min_line_number_digits lines.
24786                let min_width_for_number_on_gutter =
24787                    ch_advance * gutter_settings.min_line_number_digits as f32;
24788                self.max_line_number_width(style, window)
24789                    .max(min_width_for_number_on_gutter)
24790            } else {
24791                0.0.into()
24792            };
24793
24794            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24795            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24796
24797            let git_blame_entries_width =
24798                self.git_blame_gutter_max_author_length
24799                    .map(|max_author_length| {
24800                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24801                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24802
24803                        /// The number of characters to dedicate to gaps and margins.
24804                        const SPACING_WIDTH: usize = 4;
24805
24806                        let max_char_count = max_author_length.min(renderer.max_author_length())
24807                            + ::git::SHORT_SHA_LENGTH
24808                            + MAX_RELATIVE_TIMESTAMP.len()
24809                            + SPACING_WIDTH;
24810
24811                        ch_advance * max_char_count
24812                    });
24813
24814            let is_singleton = self.buffer_snapshot().is_singleton();
24815
24816            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24817            left_padding += if !is_singleton {
24818                ch_width * 4.0
24819            } else if show_runnables || show_breakpoints {
24820                ch_width * 3.0
24821            } else if show_git_gutter && show_line_numbers {
24822                ch_width * 2.0
24823            } else if show_git_gutter || show_line_numbers {
24824                ch_width
24825            } else {
24826                px(0.)
24827            };
24828
24829            let shows_folds = is_singleton && gutter_settings.folds;
24830
24831            let right_padding = if shows_folds && show_line_numbers {
24832                ch_width * 4.0
24833            } else if shows_folds || (!is_singleton && show_line_numbers) {
24834                ch_width * 3.0
24835            } else if show_line_numbers {
24836                ch_width
24837            } else {
24838                px(0.)
24839            };
24840
24841            GutterDimensions {
24842                left_padding,
24843                right_padding,
24844                width: line_gutter_width + left_padding + right_padding,
24845                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24846                git_blame_entries_width,
24847            }
24848        } else if self.offset_content {
24849            GutterDimensions::default_with_margin(font_id, font_size, cx)
24850        } else {
24851            GutterDimensions::default()
24852        }
24853    }
24854
24855    pub fn render_crease_toggle(
24856        &self,
24857        buffer_row: MultiBufferRow,
24858        row_contains_cursor: bool,
24859        editor: Entity<Editor>,
24860        window: &mut Window,
24861        cx: &mut App,
24862    ) -> Option<AnyElement> {
24863        let folded = self.is_line_folded(buffer_row);
24864        let mut is_foldable = false;
24865
24866        if let Some(crease) = self
24867            .crease_snapshot
24868            .query_row(buffer_row, self.buffer_snapshot())
24869        {
24870            is_foldable = true;
24871            match crease {
24872                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24873                    if let Some(render_toggle) = render_toggle {
24874                        let toggle_callback =
24875                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24876                                if folded {
24877                                    editor.update(cx, |editor, cx| {
24878                                        editor.fold_at(buffer_row, window, cx)
24879                                    });
24880                                } else {
24881                                    editor.update(cx, |editor, cx| {
24882                                        editor.unfold_at(buffer_row, window, cx)
24883                                    });
24884                                }
24885                            });
24886                        return Some((render_toggle)(
24887                            buffer_row,
24888                            folded,
24889                            toggle_callback,
24890                            window,
24891                            cx,
24892                        ));
24893                    }
24894                }
24895            }
24896        }
24897
24898        is_foldable |= self.starts_indent(buffer_row);
24899
24900        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24901            Some(
24902                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24903                    .toggle_state(folded)
24904                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24905                        if folded {
24906                            this.unfold_at(buffer_row, window, cx);
24907                        } else {
24908                            this.fold_at(buffer_row, window, cx);
24909                        }
24910                    }))
24911                    .into_any_element(),
24912            )
24913        } else {
24914            None
24915        }
24916    }
24917
24918    pub fn render_crease_trailer(
24919        &self,
24920        buffer_row: MultiBufferRow,
24921        window: &mut Window,
24922        cx: &mut App,
24923    ) -> Option<AnyElement> {
24924        let folded = self.is_line_folded(buffer_row);
24925        if let Crease::Inline { render_trailer, .. } = self
24926            .crease_snapshot
24927            .query_row(buffer_row, self.buffer_snapshot())?
24928        {
24929            let render_trailer = render_trailer.as_ref()?;
24930            Some(render_trailer(buffer_row, folded, window, cx))
24931        } else {
24932            None
24933        }
24934    }
24935
24936    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
24937        let digit_count = self.widest_line_number().ilog10() + 1;
24938        column_pixels(style, digit_count as usize, window)
24939    }
24940}
24941
24942pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
24943    let font_size = style.text.font_size.to_pixels(window.rem_size());
24944    let layout = window.text_system().shape_line(
24945        SharedString::from(" ".repeat(column)),
24946        font_size,
24947        &[TextRun {
24948            len: column,
24949            font: style.text.font(),
24950            color: Hsla::default(),
24951            ..Default::default()
24952        }],
24953        None,
24954    );
24955
24956    layout.width
24957}
24958
24959impl Deref for EditorSnapshot {
24960    type Target = DisplaySnapshot;
24961
24962    fn deref(&self) -> &Self::Target {
24963        &self.display_snapshot
24964    }
24965}
24966
24967#[derive(Clone, Debug, PartialEq, Eq)]
24968pub enum EditorEvent {
24969    InputIgnored {
24970        text: Arc<str>,
24971    },
24972    InputHandled {
24973        utf16_range_to_replace: Option<Range<isize>>,
24974        text: Arc<str>,
24975    },
24976    ExcerptsAdded {
24977        buffer: Entity<Buffer>,
24978        predecessor: ExcerptId,
24979        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24980    },
24981    ExcerptsRemoved {
24982        ids: Vec<ExcerptId>,
24983        removed_buffer_ids: Vec<BufferId>,
24984    },
24985    BufferFoldToggled {
24986        ids: Vec<ExcerptId>,
24987        folded: bool,
24988    },
24989    ExcerptsEdited {
24990        ids: Vec<ExcerptId>,
24991    },
24992    ExcerptsExpanded {
24993        ids: Vec<ExcerptId>,
24994    },
24995    BufferEdited,
24996    Edited {
24997        transaction_id: clock::Lamport,
24998    },
24999    Reparsed(BufferId),
25000    Focused,
25001    FocusedIn,
25002    Blurred,
25003    DirtyChanged,
25004    Saved,
25005    TitleChanged,
25006    SelectionsChanged {
25007        local: bool,
25008    },
25009    ScrollPositionChanged {
25010        local: bool,
25011        autoscroll: bool,
25012    },
25013    TransactionUndone {
25014        transaction_id: clock::Lamport,
25015    },
25016    TransactionBegun {
25017        transaction_id: clock::Lamport,
25018    },
25019    CursorShapeChanged,
25020    BreadcrumbsChanged,
25021    PushedToNavHistory {
25022        anchor: Anchor,
25023        is_deactivate: bool,
25024    },
25025}
25026
25027impl EventEmitter<EditorEvent> for Editor {}
25028
25029impl Focusable for Editor {
25030    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25031        self.focus_handle.clone()
25032    }
25033}
25034
25035impl Render for Editor {
25036    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25037        EditorElement::new(&cx.entity(), self.create_style(cx))
25038    }
25039}
25040
25041impl EntityInputHandler for Editor {
25042    fn text_for_range(
25043        &mut self,
25044        range_utf16: Range<usize>,
25045        adjusted_range: &mut Option<Range<usize>>,
25046        _: &mut Window,
25047        cx: &mut Context<Self>,
25048    ) -> Option<String> {
25049        let snapshot = self.buffer.read(cx).read(cx);
25050        let start = snapshot.clip_offset_utf16(
25051            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25052            Bias::Left,
25053        );
25054        let end = snapshot.clip_offset_utf16(
25055            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25056            Bias::Right,
25057        );
25058        if (start.0.0..end.0.0) != range_utf16 {
25059            adjusted_range.replace(start.0.0..end.0.0);
25060        }
25061        Some(snapshot.text_for_range(start..end).collect())
25062    }
25063
25064    fn selected_text_range(
25065        &mut self,
25066        ignore_disabled_input: bool,
25067        _: &mut Window,
25068        cx: &mut Context<Self>,
25069    ) -> Option<UTF16Selection> {
25070        // Prevent the IME menu from appearing when holding down an alphabetic key
25071        // while input is disabled.
25072        if !ignore_disabled_input && !self.input_enabled {
25073            return None;
25074        }
25075
25076        let selection = self
25077            .selections
25078            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25079        let range = selection.range();
25080
25081        Some(UTF16Selection {
25082            range: range.start.0.0..range.end.0.0,
25083            reversed: selection.reversed,
25084        })
25085    }
25086
25087    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25088        let snapshot = self.buffer.read(cx).read(cx);
25089        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25090        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25091    }
25092
25093    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25094        self.clear_highlights::<InputComposition>(cx);
25095        self.ime_transaction.take();
25096    }
25097
25098    fn replace_text_in_range(
25099        &mut self,
25100        range_utf16: Option<Range<usize>>,
25101        text: &str,
25102        window: &mut Window,
25103        cx: &mut Context<Self>,
25104    ) {
25105        if !self.input_enabled {
25106            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25107            return;
25108        }
25109
25110        self.transact(window, cx, |this, window, cx| {
25111            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25112                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25113                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25114                Some(this.selection_replacement_ranges(range_utf16, cx))
25115            } else {
25116                this.marked_text_ranges(cx)
25117            };
25118
25119            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25120                let newest_selection_id = this.selections.newest_anchor().id;
25121                this.selections
25122                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25123                    .iter()
25124                    .zip(ranges_to_replace.iter())
25125                    .find_map(|(selection, range)| {
25126                        if selection.id == newest_selection_id {
25127                            Some(
25128                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25129                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25130                            )
25131                        } else {
25132                            None
25133                        }
25134                    })
25135            });
25136
25137            cx.emit(EditorEvent::InputHandled {
25138                utf16_range_to_replace: range_to_replace,
25139                text: text.into(),
25140            });
25141
25142            if let Some(new_selected_ranges) = new_selected_ranges {
25143                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25144                    selections.select_ranges(new_selected_ranges)
25145                });
25146                this.backspace(&Default::default(), window, cx);
25147            }
25148
25149            this.handle_input(text, window, cx);
25150        });
25151
25152        if let Some(transaction) = self.ime_transaction {
25153            self.buffer.update(cx, |buffer, cx| {
25154                buffer.group_until_transaction(transaction, cx);
25155            });
25156        }
25157
25158        self.unmark_text(window, cx);
25159    }
25160
25161    fn replace_and_mark_text_in_range(
25162        &mut self,
25163        range_utf16: Option<Range<usize>>,
25164        text: &str,
25165        new_selected_range_utf16: Option<Range<usize>>,
25166        window: &mut Window,
25167        cx: &mut Context<Self>,
25168    ) {
25169        if !self.input_enabled {
25170            return;
25171        }
25172
25173        let transaction = self.transact(window, cx, |this, window, cx| {
25174            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25175                let snapshot = this.buffer.read(cx).read(cx);
25176                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25177                    for marked_range in &mut marked_ranges {
25178                        marked_range.end = marked_range.start + relative_range_utf16.end;
25179                        marked_range.start += relative_range_utf16.start;
25180                        marked_range.start =
25181                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25182                        marked_range.end =
25183                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25184                    }
25185                }
25186                Some(marked_ranges)
25187            } else if let Some(range_utf16) = range_utf16 {
25188                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25189                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25190                Some(this.selection_replacement_ranges(range_utf16, cx))
25191            } else {
25192                None
25193            };
25194
25195            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25196                let newest_selection_id = this.selections.newest_anchor().id;
25197                this.selections
25198                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25199                    .iter()
25200                    .zip(ranges_to_replace.iter())
25201                    .find_map(|(selection, range)| {
25202                        if selection.id == newest_selection_id {
25203                            Some(
25204                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25205                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25206                            )
25207                        } else {
25208                            None
25209                        }
25210                    })
25211            });
25212
25213            cx.emit(EditorEvent::InputHandled {
25214                utf16_range_to_replace: range_to_replace,
25215                text: text.into(),
25216            });
25217
25218            if let Some(ranges) = ranges_to_replace {
25219                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25220                    s.select_ranges(ranges)
25221                });
25222            }
25223
25224            let marked_ranges = {
25225                let snapshot = this.buffer.read(cx).read(cx);
25226                this.selections
25227                    .disjoint_anchors_arc()
25228                    .iter()
25229                    .map(|selection| {
25230                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25231                    })
25232                    .collect::<Vec<_>>()
25233            };
25234
25235            if text.is_empty() {
25236                this.unmark_text(window, cx);
25237            } else {
25238                this.highlight_text::<InputComposition>(
25239                    marked_ranges.clone(),
25240                    HighlightStyle {
25241                        underline: Some(UnderlineStyle {
25242                            thickness: px(1.),
25243                            color: None,
25244                            wavy: false,
25245                        }),
25246                        ..Default::default()
25247                    },
25248                    cx,
25249                );
25250            }
25251
25252            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25253            let use_autoclose = this.use_autoclose;
25254            let use_auto_surround = this.use_auto_surround;
25255            this.set_use_autoclose(false);
25256            this.set_use_auto_surround(false);
25257            this.handle_input(text, window, cx);
25258            this.set_use_autoclose(use_autoclose);
25259            this.set_use_auto_surround(use_auto_surround);
25260
25261            if let Some(new_selected_range) = new_selected_range_utf16 {
25262                let snapshot = this.buffer.read(cx).read(cx);
25263                let new_selected_ranges = marked_ranges
25264                    .into_iter()
25265                    .map(|marked_range| {
25266                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25267                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25268                            insertion_start.0 + new_selected_range.start,
25269                        ));
25270                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25271                            insertion_start.0 + new_selected_range.end,
25272                        ));
25273                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25274                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25275                    })
25276                    .collect::<Vec<_>>();
25277
25278                drop(snapshot);
25279                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25280                    selections.select_ranges(new_selected_ranges)
25281                });
25282            }
25283        });
25284
25285        self.ime_transaction = self.ime_transaction.or(transaction);
25286        if let Some(transaction) = self.ime_transaction {
25287            self.buffer.update(cx, |buffer, cx| {
25288                buffer.group_until_transaction(transaction, cx);
25289            });
25290        }
25291
25292        if self.text_highlights::<InputComposition>(cx).is_none() {
25293            self.ime_transaction.take();
25294        }
25295    }
25296
25297    fn bounds_for_range(
25298        &mut self,
25299        range_utf16: Range<usize>,
25300        element_bounds: gpui::Bounds<Pixels>,
25301        window: &mut Window,
25302        cx: &mut Context<Self>,
25303    ) -> Option<gpui::Bounds<Pixels>> {
25304        let text_layout_details = self.text_layout_details(window);
25305        let CharacterDimensions {
25306            em_width,
25307            em_advance,
25308            line_height,
25309        } = self.character_dimensions(window);
25310
25311        let snapshot = self.snapshot(window, cx);
25312        let scroll_position = snapshot.scroll_position();
25313        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25314
25315        let start =
25316            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25317        let x = Pixels::from(
25318            ScrollOffset::from(
25319                snapshot.x_for_display_point(start, &text_layout_details)
25320                    + self.gutter_dimensions.full_width(),
25321            ) - scroll_left,
25322        );
25323        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25324
25325        Some(Bounds {
25326            origin: element_bounds.origin + point(x, y),
25327            size: size(em_width, line_height),
25328        })
25329    }
25330
25331    fn character_index_for_point(
25332        &mut self,
25333        point: gpui::Point<Pixels>,
25334        _window: &mut Window,
25335        _cx: &mut Context<Self>,
25336    ) -> Option<usize> {
25337        let position_map = self.last_position_map.as_ref()?;
25338        if !position_map.text_hitbox.contains(&point) {
25339            return None;
25340        }
25341        let display_point = position_map.point_for_position(point).previous_valid;
25342        let anchor = position_map
25343            .snapshot
25344            .display_point_to_anchor(display_point, Bias::Left);
25345        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25346        Some(utf16_offset.0.0)
25347    }
25348
25349    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25350        self.input_enabled
25351    }
25352}
25353
25354trait SelectionExt {
25355    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25356    fn spanned_rows(
25357        &self,
25358        include_end_if_at_line_start: bool,
25359        map: &DisplaySnapshot,
25360    ) -> Range<MultiBufferRow>;
25361}
25362
25363impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25364    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25365        let start = self
25366            .start
25367            .to_point(map.buffer_snapshot())
25368            .to_display_point(map);
25369        let end = self
25370            .end
25371            .to_point(map.buffer_snapshot())
25372            .to_display_point(map);
25373        if self.reversed {
25374            end..start
25375        } else {
25376            start..end
25377        }
25378    }
25379
25380    fn spanned_rows(
25381        &self,
25382        include_end_if_at_line_start: bool,
25383        map: &DisplaySnapshot,
25384    ) -> Range<MultiBufferRow> {
25385        let start = self.start.to_point(map.buffer_snapshot());
25386        let mut end = self.end.to_point(map.buffer_snapshot());
25387        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25388            end.row -= 1;
25389        }
25390
25391        let buffer_start = map.prev_line_boundary(start).0;
25392        let buffer_end = map.next_line_boundary(end).0;
25393        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25394    }
25395}
25396
25397impl<T: InvalidationRegion> InvalidationStack<T> {
25398    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25399    where
25400        S: Clone + ToOffset,
25401    {
25402        while let Some(region) = self.last() {
25403            let all_selections_inside_invalidation_ranges =
25404                if selections.len() == region.ranges().len() {
25405                    selections
25406                        .iter()
25407                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25408                        .all(|(selection, invalidation_range)| {
25409                            let head = selection.head().to_offset(buffer);
25410                            invalidation_range.start <= head && invalidation_range.end >= head
25411                        })
25412                } else {
25413                    false
25414                };
25415
25416            if all_selections_inside_invalidation_ranges {
25417                break;
25418            } else {
25419                self.pop();
25420            }
25421        }
25422    }
25423}
25424
25425impl<T> Default for InvalidationStack<T> {
25426    fn default() -> Self {
25427        Self(Default::default())
25428    }
25429}
25430
25431impl<T> Deref for InvalidationStack<T> {
25432    type Target = Vec<T>;
25433
25434    fn deref(&self) -> &Self::Target {
25435        &self.0
25436    }
25437}
25438
25439impl<T> DerefMut for InvalidationStack<T> {
25440    fn deref_mut(&mut self) -> &mut Self::Target {
25441        &mut self.0
25442    }
25443}
25444
25445impl InvalidationRegion for SnippetState {
25446    fn ranges(&self) -> &[Range<Anchor>] {
25447        &self.ranges[self.active_index]
25448    }
25449}
25450
25451fn edit_prediction_edit_text(
25452    current_snapshot: &BufferSnapshot,
25453    edits: &[(Range<Anchor>, impl AsRef<str>)],
25454    edit_preview: &EditPreview,
25455    include_deletions: bool,
25456    cx: &App,
25457) -> HighlightedText {
25458    let edits = edits
25459        .iter()
25460        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25461        .collect::<Vec<_>>();
25462
25463    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25464}
25465
25466fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25467    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25468    // Just show the raw edit text with basic styling
25469    let mut text = String::new();
25470    let mut highlights = Vec::new();
25471
25472    let insertion_highlight_style = HighlightStyle {
25473        color: Some(cx.theme().colors().text),
25474        ..Default::default()
25475    };
25476
25477    for (_, edit_text) in edits {
25478        let start_offset = text.len();
25479        text.push_str(edit_text);
25480        let end_offset = text.len();
25481
25482        if start_offset < end_offset {
25483            highlights.push((start_offset..end_offset, insertion_highlight_style));
25484        }
25485    }
25486
25487    HighlightedText {
25488        text: text.into(),
25489        highlights,
25490    }
25491}
25492
25493pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25494    match severity {
25495        lsp::DiagnosticSeverity::ERROR => colors.error,
25496        lsp::DiagnosticSeverity::WARNING => colors.warning,
25497        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25498        lsp::DiagnosticSeverity::HINT => colors.info,
25499        _ => colors.ignored,
25500    }
25501}
25502
25503pub fn styled_runs_for_code_label<'a>(
25504    label: &'a CodeLabel,
25505    syntax_theme: &'a theme::SyntaxTheme,
25506    local_player: &'a theme::PlayerColor,
25507) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25508    let fade_out = HighlightStyle {
25509        fade_out: Some(0.35),
25510        ..Default::default()
25511    };
25512
25513    let mut prev_end = label.filter_range.end;
25514    label
25515        .runs
25516        .iter()
25517        .enumerate()
25518        .flat_map(move |(ix, (range, highlight_id))| {
25519            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25520                HighlightStyle {
25521                    color: Some(local_player.cursor),
25522                    ..Default::default()
25523                }
25524            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25525                HighlightStyle {
25526                    background_color: Some(local_player.selection),
25527                    ..Default::default()
25528                }
25529            } else if let Some(style) = highlight_id.style(syntax_theme) {
25530                style
25531            } else {
25532                return Default::default();
25533            };
25534            let muted_style = style.highlight(fade_out);
25535
25536            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25537            if range.start >= label.filter_range.end {
25538                if range.start > prev_end {
25539                    runs.push((prev_end..range.start, fade_out));
25540                }
25541                runs.push((range.clone(), muted_style));
25542            } else if range.end <= label.filter_range.end {
25543                runs.push((range.clone(), style));
25544            } else {
25545                runs.push((range.start..label.filter_range.end, style));
25546                runs.push((label.filter_range.end..range.end, muted_style));
25547            }
25548            prev_end = cmp::max(prev_end, range.end);
25549
25550            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25551                runs.push((prev_end..label.text.len(), fade_out));
25552            }
25553
25554            runs
25555        })
25556}
25557
25558pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25559    let mut prev_index = 0;
25560    let mut prev_codepoint: Option<char> = None;
25561    text.char_indices()
25562        .chain([(text.len(), '\0')])
25563        .filter_map(move |(index, codepoint)| {
25564            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25565            let is_boundary = index == text.len()
25566                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25567                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25568            if is_boundary {
25569                let chunk = &text[prev_index..index];
25570                prev_index = index;
25571                Some(chunk)
25572            } else {
25573                None
25574            }
25575        })
25576}
25577
25578/// Given a string of text immediately before the cursor, iterates over possible
25579/// strings a snippet could match to. More precisely: returns an iterator over
25580/// suffixes of `text` created by splitting at word boundaries (before & after
25581/// every non-word character).
25582///
25583/// Shorter suffixes are returned first.
25584pub(crate) fn snippet_candidate_suffixes(
25585    text: &str,
25586    is_word_char: impl Fn(char) -> bool,
25587) -> impl std::iter::Iterator<Item = &str> {
25588    let mut prev_index = text.len();
25589    let mut prev_codepoint = None;
25590    text.char_indices()
25591        .rev()
25592        .chain([(0, '\0')])
25593        .filter_map(move |(index, codepoint)| {
25594            let prev_index = std::mem::replace(&mut prev_index, index);
25595            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25596            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25597                None
25598            } else {
25599                let chunk = &text[prev_index..]; // go to end of string
25600                Some(chunk)
25601            }
25602        })
25603}
25604
25605pub trait RangeToAnchorExt: Sized {
25606    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25607
25608    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25609        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25610        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25611    }
25612}
25613
25614impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25615    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25616        let start_offset = self.start.to_offset(snapshot);
25617        let end_offset = self.end.to_offset(snapshot);
25618        if start_offset == end_offset {
25619            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25620        } else {
25621            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25622        }
25623    }
25624}
25625
25626pub trait RowExt {
25627    fn as_f64(&self) -> f64;
25628
25629    fn next_row(&self) -> Self;
25630
25631    fn previous_row(&self) -> Self;
25632
25633    fn minus(&self, other: Self) -> u32;
25634}
25635
25636impl RowExt for DisplayRow {
25637    fn as_f64(&self) -> f64 {
25638        self.0 as _
25639    }
25640
25641    fn next_row(&self) -> Self {
25642        Self(self.0 + 1)
25643    }
25644
25645    fn previous_row(&self) -> Self {
25646        Self(self.0.saturating_sub(1))
25647    }
25648
25649    fn minus(&self, other: Self) -> u32 {
25650        self.0 - other.0
25651    }
25652}
25653
25654impl RowExt for MultiBufferRow {
25655    fn as_f64(&self) -> f64 {
25656        self.0 as _
25657    }
25658
25659    fn next_row(&self) -> Self {
25660        Self(self.0 + 1)
25661    }
25662
25663    fn previous_row(&self) -> Self {
25664        Self(self.0.saturating_sub(1))
25665    }
25666
25667    fn minus(&self, other: Self) -> u32 {
25668        self.0 - other.0
25669    }
25670}
25671
25672trait RowRangeExt {
25673    type Row;
25674
25675    fn len(&self) -> usize;
25676
25677    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25678}
25679
25680impl RowRangeExt for Range<MultiBufferRow> {
25681    type Row = MultiBufferRow;
25682
25683    fn len(&self) -> usize {
25684        (self.end.0 - self.start.0) as usize
25685    }
25686
25687    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25688        (self.start.0..self.end.0).map(MultiBufferRow)
25689    }
25690}
25691
25692impl RowRangeExt for Range<DisplayRow> {
25693    type Row = DisplayRow;
25694
25695    fn len(&self) -> usize {
25696        (self.end.0 - self.start.0) as usize
25697    }
25698
25699    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25700        (self.start.0..self.end.0).map(DisplayRow)
25701    }
25702}
25703
25704/// If select range has more than one line, we
25705/// just point the cursor to range.start.
25706fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25707    if range.start.row == range.end.row {
25708        range
25709    } else {
25710        range.start..range.start
25711    }
25712}
25713pub struct KillRing(ClipboardItem);
25714impl Global for KillRing {}
25715
25716const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25717
25718enum BreakpointPromptEditAction {
25719    Log,
25720    Condition,
25721    HitCondition,
25722}
25723
25724struct BreakpointPromptEditor {
25725    pub(crate) prompt: Entity<Editor>,
25726    editor: WeakEntity<Editor>,
25727    breakpoint_anchor: Anchor,
25728    breakpoint: Breakpoint,
25729    edit_action: BreakpointPromptEditAction,
25730    block_ids: HashSet<CustomBlockId>,
25731    editor_margins: Arc<Mutex<EditorMargins>>,
25732    _subscriptions: Vec<Subscription>,
25733}
25734
25735impl BreakpointPromptEditor {
25736    const MAX_LINES: u8 = 4;
25737
25738    fn new(
25739        editor: WeakEntity<Editor>,
25740        breakpoint_anchor: Anchor,
25741        breakpoint: Breakpoint,
25742        edit_action: BreakpointPromptEditAction,
25743        window: &mut Window,
25744        cx: &mut Context<Self>,
25745    ) -> Self {
25746        let base_text = match edit_action {
25747            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25748            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25749            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25750        }
25751        .map(|msg| msg.to_string())
25752        .unwrap_or_default();
25753
25754        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25755        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25756
25757        let prompt = cx.new(|cx| {
25758            let mut prompt = Editor::new(
25759                EditorMode::AutoHeight {
25760                    min_lines: 1,
25761                    max_lines: Some(Self::MAX_LINES as usize),
25762                },
25763                buffer,
25764                None,
25765                window,
25766                cx,
25767            );
25768            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25769            prompt.set_show_cursor_when_unfocused(false, cx);
25770            prompt.set_placeholder_text(
25771                match edit_action {
25772                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25773                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25774                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25775                },
25776                window,
25777                cx,
25778            );
25779
25780            prompt
25781        });
25782
25783        Self {
25784            prompt,
25785            editor,
25786            breakpoint_anchor,
25787            breakpoint,
25788            edit_action,
25789            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25790            block_ids: Default::default(),
25791            _subscriptions: vec![],
25792        }
25793    }
25794
25795    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25796        self.block_ids.extend(block_ids)
25797    }
25798
25799    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25800        if let Some(editor) = self.editor.upgrade() {
25801            let message = self
25802                .prompt
25803                .read(cx)
25804                .buffer
25805                .read(cx)
25806                .as_singleton()
25807                .expect("A multi buffer in breakpoint prompt isn't possible")
25808                .read(cx)
25809                .as_rope()
25810                .to_string();
25811
25812            editor.update(cx, |editor, cx| {
25813                editor.edit_breakpoint_at_anchor(
25814                    self.breakpoint_anchor,
25815                    self.breakpoint.clone(),
25816                    match self.edit_action {
25817                        BreakpointPromptEditAction::Log => {
25818                            BreakpointEditAction::EditLogMessage(message.into())
25819                        }
25820                        BreakpointPromptEditAction::Condition => {
25821                            BreakpointEditAction::EditCondition(message.into())
25822                        }
25823                        BreakpointPromptEditAction::HitCondition => {
25824                            BreakpointEditAction::EditHitCondition(message.into())
25825                        }
25826                    },
25827                    cx,
25828                );
25829
25830                editor.remove_blocks(self.block_ids.clone(), None, cx);
25831                cx.focus_self(window);
25832            });
25833        }
25834    }
25835
25836    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25837        self.editor
25838            .update(cx, |editor, cx| {
25839                editor.remove_blocks(self.block_ids.clone(), None, cx);
25840                window.focus(&editor.focus_handle);
25841            })
25842            .log_err();
25843    }
25844
25845    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25846        let settings = ThemeSettings::get_global(cx);
25847        let text_style = TextStyle {
25848            color: if self.prompt.read(cx).read_only(cx) {
25849                cx.theme().colors().text_disabled
25850            } else {
25851                cx.theme().colors().text
25852            },
25853            font_family: settings.buffer_font.family.clone(),
25854            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25855            font_size: settings.buffer_font_size(cx).into(),
25856            font_weight: settings.buffer_font.weight,
25857            line_height: relative(settings.buffer_line_height.value()),
25858            ..Default::default()
25859        };
25860        EditorElement::new(
25861            &self.prompt,
25862            EditorStyle {
25863                background: cx.theme().colors().editor_background,
25864                local_player: cx.theme().players().local(),
25865                text: text_style,
25866                ..Default::default()
25867            },
25868        )
25869    }
25870}
25871
25872impl Render for BreakpointPromptEditor {
25873    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25874        let editor_margins = *self.editor_margins.lock();
25875        let gutter_dimensions = editor_margins.gutter;
25876        h_flex()
25877            .key_context("Editor")
25878            .bg(cx.theme().colors().editor_background)
25879            .border_y_1()
25880            .border_color(cx.theme().status().info_border)
25881            .size_full()
25882            .py(window.line_height() / 2.5)
25883            .on_action(cx.listener(Self::confirm))
25884            .on_action(cx.listener(Self::cancel))
25885            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25886            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25887    }
25888}
25889
25890impl Focusable for BreakpointPromptEditor {
25891    fn focus_handle(&self, cx: &App) -> FocusHandle {
25892        self.prompt.focus_handle(cx)
25893    }
25894}
25895
25896fn all_edits_insertions_or_deletions(
25897    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25898    snapshot: &MultiBufferSnapshot,
25899) -> bool {
25900    let mut all_insertions = true;
25901    let mut all_deletions = true;
25902
25903    for (range, new_text) in edits.iter() {
25904        let range_is_empty = range.to_offset(snapshot).is_empty();
25905        let text_is_empty = new_text.is_empty();
25906
25907        if range_is_empty != text_is_empty {
25908            if range_is_empty {
25909                all_deletions = false;
25910            } else {
25911                all_insertions = false;
25912            }
25913        } else {
25914            return false;
25915        }
25916
25917        if !all_insertions && !all_deletions {
25918            return false;
25919        }
25920    }
25921    all_insertions || all_deletions
25922}
25923
25924struct MissingEditPredictionKeybindingTooltip;
25925
25926impl Render for MissingEditPredictionKeybindingTooltip {
25927    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25928        ui::tooltip_container(cx, |container, cx| {
25929            container
25930                .flex_shrink_0()
25931                .max_w_80()
25932                .min_h(rems_from_px(124.))
25933                .justify_between()
25934                .child(
25935                    v_flex()
25936                        .flex_1()
25937                        .text_ui_sm(cx)
25938                        .child(Label::new("Conflict with Accept Keybinding"))
25939                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25940                )
25941                .child(
25942                    h_flex()
25943                        .pb_1()
25944                        .gap_1()
25945                        .items_end()
25946                        .w_full()
25947                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25948                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25949                        }))
25950                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25951                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25952                        })),
25953                )
25954        })
25955    }
25956}
25957
25958#[derive(Debug, Clone, Copy, PartialEq)]
25959pub struct LineHighlight {
25960    pub background: Background,
25961    pub border: Option<gpui::Hsla>,
25962    pub include_gutter: bool,
25963    pub type_id: Option<TypeId>,
25964}
25965
25966struct LineManipulationResult {
25967    pub new_text: String,
25968    pub line_count_before: usize,
25969    pub line_count_after: usize,
25970}
25971
25972fn render_diff_hunk_controls(
25973    row: u32,
25974    status: &DiffHunkStatus,
25975    hunk_range: Range<Anchor>,
25976    is_created_file: bool,
25977    line_height: Pixels,
25978    editor: &Entity<Editor>,
25979    _window: &mut Window,
25980    cx: &mut App,
25981) -> AnyElement {
25982    h_flex()
25983        .h(line_height)
25984        .mr_1()
25985        .gap_1()
25986        .px_0p5()
25987        .pb_1()
25988        .border_x_1()
25989        .border_b_1()
25990        .border_color(cx.theme().colors().border_variant)
25991        .rounded_b_lg()
25992        .bg(cx.theme().colors().editor_background)
25993        .gap_1()
25994        .block_mouse_except_scroll()
25995        .shadow_md()
25996        .child(if status.has_secondary_hunk() {
25997            Button::new(("stage", row as u64), "Stage")
25998                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25999                .tooltip({
26000                    let focus_handle = editor.focus_handle(cx);
26001                    move |_window, cx| {
26002                        Tooltip::for_action_in(
26003                            "Stage Hunk",
26004                            &::git::ToggleStaged,
26005                            &focus_handle,
26006                            cx,
26007                        )
26008                    }
26009                })
26010                .on_click({
26011                    let editor = editor.clone();
26012                    move |_event, _window, cx| {
26013                        editor.update(cx, |editor, cx| {
26014                            editor.stage_or_unstage_diff_hunks(
26015                                true,
26016                                vec![hunk_range.start..hunk_range.start],
26017                                cx,
26018                            );
26019                        });
26020                    }
26021                })
26022        } else {
26023            Button::new(("unstage", row as u64), "Unstage")
26024                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26025                .tooltip({
26026                    let focus_handle = editor.focus_handle(cx);
26027                    move |_window, cx| {
26028                        Tooltip::for_action_in(
26029                            "Unstage Hunk",
26030                            &::git::ToggleStaged,
26031                            &focus_handle,
26032                            cx,
26033                        )
26034                    }
26035                })
26036                .on_click({
26037                    let editor = editor.clone();
26038                    move |_event, _window, cx| {
26039                        editor.update(cx, |editor, cx| {
26040                            editor.stage_or_unstage_diff_hunks(
26041                                false,
26042                                vec![hunk_range.start..hunk_range.start],
26043                                cx,
26044                            );
26045                        });
26046                    }
26047                })
26048        })
26049        .child(
26050            Button::new(("restore", row as u64), "Restore")
26051                .tooltip({
26052                    let focus_handle = editor.focus_handle(cx);
26053                    move |_window, cx| {
26054                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26055                    }
26056                })
26057                .on_click({
26058                    let editor = editor.clone();
26059                    move |_event, window, cx| {
26060                        editor.update(cx, |editor, cx| {
26061                            let snapshot = editor.snapshot(window, cx);
26062                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26063                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26064                        });
26065                    }
26066                })
26067                .disabled(is_created_file),
26068        )
26069        .when(
26070            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26071            |el| {
26072                el.child(
26073                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26074                        .shape(IconButtonShape::Square)
26075                        .icon_size(IconSize::Small)
26076                        // .disabled(!has_multiple_hunks)
26077                        .tooltip({
26078                            let focus_handle = editor.focus_handle(cx);
26079                            move |_window, cx| {
26080                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26081                            }
26082                        })
26083                        .on_click({
26084                            let editor = editor.clone();
26085                            move |_event, window, cx| {
26086                                editor.update(cx, |editor, cx| {
26087                                    let snapshot = editor.snapshot(window, cx);
26088                                    let position =
26089                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26090                                    editor.go_to_hunk_before_or_after_position(
26091                                        &snapshot,
26092                                        position,
26093                                        Direction::Next,
26094                                        window,
26095                                        cx,
26096                                    );
26097                                    editor.expand_selected_diff_hunks(cx);
26098                                });
26099                            }
26100                        }),
26101                )
26102                .child(
26103                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26104                        .shape(IconButtonShape::Square)
26105                        .icon_size(IconSize::Small)
26106                        // .disabled(!has_multiple_hunks)
26107                        .tooltip({
26108                            let focus_handle = editor.focus_handle(cx);
26109                            move |_window, cx| {
26110                                Tooltip::for_action_in(
26111                                    "Previous Hunk",
26112                                    &GoToPreviousHunk,
26113                                    &focus_handle,
26114                                    cx,
26115                                )
26116                            }
26117                        })
26118                        .on_click({
26119                            let editor = editor.clone();
26120                            move |_event, window, cx| {
26121                                editor.update(cx, |editor, cx| {
26122                                    let snapshot = editor.snapshot(window, cx);
26123                                    let point =
26124                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26125                                    editor.go_to_hunk_before_or_after_position(
26126                                        &snapshot,
26127                                        point,
26128                                        Direction::Prev,
26129                                        window,
26130                                        cx,
26131                                    );
26132                                    editor.expand_selected_diff_hunks(cx);
26133                                });
26134                            }
26135                        }),
26136                )
26137            },
26138        )
26139        .into_any_element()
26140}
26141
26142pub fn multibuffer_context_lines(cx: &App) -> u32 {
26143    EditorSettings::try_get(cx)
26144        .map(|settings| settings.excerpt_context_lines)
26145        .unwrap_or(2)
26146        .min(32)
26147}