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::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus};
   77use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   78use anyhow::{Context as _, Result, anyhow, bail};
   79use blink_manager::BlinkManager;
   80use buffer_diff::DiffHunkStatus;
   81use client::{Collaborator, ParticipantIndex, parse_zed_link};
   82use clock::ReplicaId;
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   88use convert_case::{Case, Casing};
   89use dap::TelemetrySpawnLocation;
   90use display_map::*;
   91use edit_prediction_types::{
   92    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionGranularity,
   93};
   94use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   95use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   96use futures::{
   97    FutureExt, StreamExt as _,
   98    future::{self, Shared, join},
   99    stream::FuturesUnordered,
  100};
  101use fuzzy::{StringMatch, StringMatchCandidate};
  102use git::blame::{GitBlame, GlobalBlameRenderer};
  103use gpui::{
  104    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  105    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  106    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  107    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  108    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage,
  109    Render, ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextRun,
  110    TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle,
  111    WeakEntity, WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative,
  112    size,
  113};
  114use hover_links::{HoverLink, HoveredLinkState, find_file};
  115use hover_popover::{HoverState, hide_hover};
  116use indent_guides::ActiveIndentGuidesState;
  117use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  118use itertools::{Either, Itertools};
  119use language::{
  120    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  121    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  122    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  123    IndentSize, Language, LanguageName, LanguageRegistry, LanguageScope, OffsetRangeExt,
  124    OutlineItem, Point, Runnable, Selection, SelectionGoal, TextObject, TransactionId,
  125    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    .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    /// Whether the cursor is offset one character to the left when something is
 1111    /// selected (needed for vim visual mode)
 1112    cursor_offset_on_selection: bool,
 1113    current_line_highlight: Option<CurrentLineHighlight>,
 1114    pub collapse_matches: bool,
 1115    autoindent_mode: Option<AutoindentMode>,
 1116    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1117    input_enabled: bool,
 1118    use_modal_editing: bool,
 1119    read_only: bool,
 1120    leader_id: Option<CollaboratorId>,
 1121    remote_id: Option<ViewId>,
 1122    pub hover_state: HoverState,
 1123    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1124    prev_pressure_stage: Option<PressureStage>,
 1125    gutter_hovered: bool,
 1126    hovered_link_state: Option<HoveredLinkState>,
 1127    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1128    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1129    active_edit_prediction: Option<EditPredictionState>,
 1130    /// Used to prevent flickering as the user types while the menu is open
 1131    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1132    edit_prediction_settings: EditPredictionSettings,
 1133    edit_predictions_hidden_for_vim_mode: bool,
 1134    show_edit_predictions_override: Option<bool>,
 1135    show_completions_on_input_override: Option<bool>,
 1136    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1137    edit_prediction_preview: EditPredictionPreview,
 1138    edit_prediction_indent_conflict: bool,
 1139    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1140    next_inlay_id: usize,
 1141    next_color_inlay_id: usize,
 1142    _subscriptions: Vec<Subscription>,
 1143    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1144    gutter_dimensions: GutterDimensions,
 1145    style: Option<EditorStyle>,
 1146    text_style_refinement: Option<TextStyleRefinement>,
 1147    next_editor_action_id: EditorActionId,
 1148    editor_actions: Rc<
 1149        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1150    >,
 1151    use_autoclose: bool,
 1152    use_auto_surround: bool,
 1153    auto_replace_emoji_shortcode: bool,
 1154    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1155    show_git_blame_gutter: bool,
 1156    show_git_blame_inline: bool,
 1157    show_git_blame_inline_delay_task: Option<Task<()>>,
 1158    git_blame_inline_enabled: bool,
 1159    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1160    buffer_serialization: Option<BufferSerialization>,
 1161    show_selection_menu: Option<bool>,
 1162    blame: Option<Entity<GitBlame>>,
 1163    blame_subscription: Option<Subscription>,
 1164    custom_context_menu: Option<
 1165        Box<
 1166            dyn 'static
 1167                + Fn(
 1168                    &mut Self,
 1169                    DisplayPoint,
 1170                    &mut Window,
 1171                    &mut Context<Self>,
 1172                ) -> Option<Entity<ui::ContextMenu>>,
 1173        >,
 1174    >,
 1175    last_bounds: Option<Bounds<Pixels>>,
 1176    last_position_map: Option<Rc<PositionMap>>,
 1177    expect_bounds_change: Option<Bounds<Pixels>>,
 1178    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1179    tasks_update_task: Option<Task<()>>,
 1180    breakpoint_store: Option<Entity<BreakpointStore>>,
 1181    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1182    hovered_diff_hunk_row: Option<DisplayRow>,
 1183    pull_diagnostics_task: Task<()>,
 1184    pull_diagnostics_background_task: Task<()>,
 1185    in_project_search: bool,
 1186    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1187    breadcrumb_header: Option<String>,
 1188    focused_block: Option<FocusedBlock>,
 1189    next_scroll_position: NextScrollCursorCenterTopBottom,
 1190    addons: HashMap<TypeId, Box<dyn Addon>>,
 1191    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1192    load_diff_task: Option<Shared<Task<()>>>,
 1193    /// Whether we are temporarily displaying a diff other than git's
 1194    temporary_diff_override: bool,
 1195    selection_mark_mode: bool,
 1196    toggle_fold_multiple_buffers: Task<()>,
 1197    _scroll_cursor_center_top_bottom_task: Task<()>,
 1198    serialize_selections: Task<()>,
 1199    serialize_folds: Task<()>,
 1200    mouse_cursor_hidden: bool,
 1201    minimap: Option<Entity<Self>>,
 1202    hide_mouse_mode: HideMouseMode,
 1203    pub change_list: ChangeList,
 1204    inline_value_cache: InlineValueCache,
 1205
 1206    selection_drag_state: SelectionDragState,
 1207    colors: Option<LspColorData>,
 1208    post_scroll_update: Task<()>,
 1209    refresh_colors_task: Task<()>,
 1210    inlay_hints: Option<LspInlayHintData>,
 1211    folding_newlines: Task<()>,
 1212    select_next_is_case_sensitive: Option<bool>,
 1213    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1214    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1215    accent_data: Option<AccentData>,
 1216    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1217    use_base_text_line_numbers: bool,
 1218}
 1219
 1220#[derive(Debug, PartialEq)]
 1221struct AccentData {
 1222    colors: AccentColors,
 1223    overrides: Vec<SharedString>,
 1224}
 1225
 1226fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1227    if debounce_ms > 0 {
 1228        Some(Duration::from_millis(debounce_ms))
 1229    } else {
 1230        None
 1231    }
 1232}
 1233
 1234#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1235enum NextScrollCursorCenterTopBottom {
 1236    #[default]
 1237    Center,
 1238    Top,
 1239    Bottom,
 1240}
 1241
 1242impl NextScrollCursorCenterTopBottom {
 1243    fn next(&self) -> Self {
 1244        match self {
 1245            Self::Center => Self::Top,
 1246            Self::Top => Self::Bottom,
 1247            Self::Bottom => Self::Center,
 1248        }
 1249    }
 1250}
 1251
 1252#[derive(Clone)]
 1253pub struct EditorSnapshot {
 1254    pub mode: EditorMode,
 1255    show_gutter: bool,
 1256    offset_content: bool,
 1257    show_line_numbers: Option<bool>,
 1258    show_git_diff_gutter: Option<bool>,
 1259    show_code_actions: Option<bool>,
 1260    show_runnables: Option<bool>,
 1261    show_breakpoints: Option<bool>,
 1262    git_blame_gutter_max_author_length: Option<usize>,
 1263    pub display_snapshot: DisplaySnapshot,
 1264    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1265    is_focused: bool,
 1266    scroll_anchor: ScrollAnchor,
 1267    ongoing_scroll: OngoingScroll,
 1268    current_line_highlight: CurrentLineHighlight,
 1269    gutter_hovered: bool,
 1270}
 1271
 1272#[derive(Default, Debug, Clone, Copy)]
 1273pub struct GutterDimensions {
 1274    pub left_padding: Pixels,
 1275    pub right_padding: Pixels,
 1276    pub width: Pixels,
 1277    pub margin: Pixels,
 1278    pub git_blame_entries_width: Option<Pixels>,
 1279}
 1280
 1281impl GutterDimensions {
 1282    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1283        Self {
 1284            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1285            ..Default::default()
 1286        }
 1287    }
 1288
 1289    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1290        -cx.text_system().descent(font_id, font_size)
 1291    }
 1292    /// The full width of the space taken up by the gutter.
 1293    pub fn full_width(&self) -> Pixels {
 1294        self.margin + self.width
 1295    }
 1296
 1297    /// The width of the space reserved for the fold indicators,
 1298    /// use alongside 'justify_end' and `gutter_width` to
 1299    /// right align content with the line numbers
 1300    pub fn fold_area_width(&self) -> Pixels {
 1301        self.margin + self.right_padding
 1302    }
 1303}
 1304
 1305struct CharacterDimensions {
 1306    em_width: Pixels,
 1307    em_advance: Pixels,
 1308    line_height: Pixels,
 1309}
 1310
 1311#[derive(Debug)]
 1312pub struct RemoteSelection {
 1313    pub replica_id: ReplicaId,
 1314    pub selection: Selection<Anchor>,
 1315    pub cursor_shape: CursorShape,
 1316    pub collaborator_id: CollaboratorId,
 1317    pub line_mode: bool,
 1318    pub user_name: Option<SharedString>,
 1319    pub color: PlayerColor,
 1320}
 1321
 1322#[derive(Clone, Debug)]
 1323struct SelectionHistoryEntry {
 1324    selections: Arc<[Selection<Anchor>]>,
 1325    select_next_state: Option<SelectNextState>,
 1326    select_prev_state: Option<SelectNextState>,
 1327    add_selections_state: Option<AddSelectionsState>,
 1328}
 1329
 1330#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1331enum SelectionHistoryMode {
 1332    #[default]
 1333    Normal,
 1334    Undoing,
 1335    Redoing,
 1336    Skipping,
 1337}
 1338
 1339#[derive(Clone, PartialEq, Eq, Hash)]
 1340struct HoveredCursor {
 1341    replica_id: ReplicaId,
 1342    selection_id: usize,
 1343}
 1344
 1345#[derive(Debug)]
 1346/// SelectionEffects controls the side-effects of updating the selection.
 1347///
 1348/// The default behaviour does "what you mostly want":
 1349/// - it pushes to the nav history if the cursor moved by >10 lines
 1350/// - it re-triggers completion requests
 1351/// - it scrolls to fit
 1352///
 1353/// You might want to modify these behaviours. For example when doing a "jump"
 1354/// like go to definition, we always want to add to nav history; but when scrolling
 1355/// in vim mode we never do.
 1356///
 1357/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1358/// move.
 1359#[derive(Clone)]
 1360pub struct SelectionEffects {
 1361    nav_history: Option<bool>,
 1362    completions: bool,
 1363    scroll: Option<Autoscroll>,
 1364}
 1365
 1366impl Default for SelectionEffects {
 1367    fn default() -> Self {
 1368        Self {
 1369            nav_history: None,
 1370            completions: true,
 1371            scroll: Some(Autoscroll::fit()),
 1372        }
 1373    }
 1374}
 1375impl SelectionEffects {
 1376    pub fn scroll(scroll: Autoscroll) -> Self {
 1377        Self {
 1378            scroll: Some(scroll),
 1379            ..Default::default()
 1380        }
 1381    }
 1382
 1383    pub fn no_scroll() -> Self {
 1384        Self {
 1385            scroll: None,
 1386            ..Default::default()
 1387        }
 1388    }
 1389
 1390    pub fn completions(self, completions: bool) -> Self {
 1391        Self {
 1392            completions,
 1393            ..self
 1394        }
 1395    }
 1396
 1397    pub fn nav_history(self, nav_history: bool) -> Self {
 1398        Self {
 1399            nav_history: Some(nav_history),
 1400            ..self
 1401        }
 1402    }
 1403}
 1404
 1405struct DeferredSelectionEffectsState {
 1406    changed: bool,
 1407    effects: SelectionEffects,
 1408    old_cursor_position: Anchor,
 1409    history_entry: SelectionHistoryEntry,
 1410}
 1411
 1412#[derive(Default)]
 1413struct SelectionHistory {
 1414    #[allow(clippy::type_complexity)]
 1415    selections_by_transaction:
 1416        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1417    mode: SelectionHistoryMode,
 1418    undo_stack: VecDeque<SelectionHistoryEntry>,
 1419    redo_stack: VecDeque<SelectionHistoryEntry>,
 1420}
 1421
 1422impl SelectionHistory {
 1423    #[track_caller]
 1424    fn insert_transaction(
 1425        &mut self,
 1426        transaction_id: TransactionId,
 1427        selections: Arc<[Selection<Anchor>]>,
 1428    ) {
 1429        if selections.is_empty() {
 1430            log::error!(
 1431                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1432                std::panic::Location::caller()
 1433            );
 1434            return;
 1435        }
 1436        self.selections_by_transaction
 1437            .insert(transaction_id, (selections, None));
 1438    }
 1439
 1440    #[allow(clippy::type_complexity)]
 1441    fn transaction(
 1442        &self,
 1443        transaction_id: TransactionId,
 1444    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1445        self.selections_by_transaction.get(&transaction_id)
 1446    }
 1447
 1448    #[allow(clippy::type_complexity)]
 1449    fn transaction_mut(
 1450        &mut self,
 1451        transaction_id: TransactionId,
 1452    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1453        self.selections_by_transaction.get_mut(&transaction_id)
 1454    }
 1455
 1456    fn push(&mut self, entry: SelectionHistoryEntry) {
 1457        if !entry.selections.is_empty() {
 1458            match self.mode {
 1459                SelectionHistoryMode::Normal => {
 1460                    self.push_undo(entry);
 1461                    self.redo_stack.clear();
 1462                }
 1463                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1464                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1465                SelectionHistoryMode::Skipping => {}
 1466            }
 1467        }
 1468    }
 1469
 1470    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1471        if self
 1472            .undo_stack
 1473            .back()
 1474            .is_none_or(|e| e.selections != entry.selections)
 1475        {
 1476            self.undo_stack.push_back(entry);
 1477            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1478                self.undo_stack.pop_front();
 1479            }
 1480        }
 1481    }
 1482
 1483    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1484        if self
 1485            .redo_stack
 1486            .back()
 1487            .is_none_or(|e| e.selections != entry.selections)
 1488        {
 1489            self.redo_stack.push_back(entry);
 1490            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1491                self.redo_stack.pop_front();
 1492            }
 1493        }
 1494    }
 1495}
 1496
 1497#[derive(Clone, Copy)]
 1498pub struct RowHighlightOptions {
 1499    pub autoscroll: bool,
 1500    pub include_gutter: bool,
 1501}
 1502
 1503impl Default for RowHighlightOptions {
 1504    fn default() -> Self {
 1505        Self {
 1506            autoscroll: Default::default(),
 1507            include_gutter: true,
 1508        }
 1509    }
 1510}
 1511
 1512struct RowHighlight {
 1513    index: usize,
 1514    range: Range<Anchor>,
 1515    color: Hsla,
 1516    options: RowHighlightOptions,
 1517    type_id: TypeId,
 1518}
 1519
 1520#[derive(Clone, Debug)]
 1521struct AddSelectionsState {
 1522    groups: Vec<AddSelectionsGroup>,
 1523}
 1524
 1525#[derive(Clone, Debug)]
 1526struct AddSelectionsGroup {
 1527    above: bool,
 1528    stack: Vec<usize>,
 1529}
 1530
 1531#[derive(Clone)]
 1532struct SelectNextState {
 1533    query: AhoCorasick,
 1534    wordwise: bool,
 1535    done: bool,
 1536}
 1537
 1538impl std::fmt::Debug for SelectNextState {
 1539    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1540        f.debug_struct(std::any::type_name::<Self>())
 1541            .field("wordwise", &self.wordwise)
 1542            .field("done", &self.done)
 1543            .finish()
 1544    }
 1545}
 1546
 1547#[derive(Debug)]
 1548struct AutocloseRegion {
 1549    selection_id: usize,
 1550    range: Range<Anchor>,
 1551    pair: BracketPair,
 1552}
 1553
 1554#[derive(Debug)]
 1555struct SnippetState {
 1556    ranges: Vec<Vec<Range<Anchor>>>,
 1557    active_index: usize,
 1558    choices: Vec<Option<Vec<String>>>,
 1559}
 1560
 1561#[doc(hidden)]
 1562pub struct RenameState {
 1563    pub range: Range<Anchor>,
 1564    pub old_name: Arc<str>,
 1565    pub editor: Entity<Editor>,
 1566    block_id: CustomBlockId,
 1567}
 1568
 1569struct InvalidationStack<T>(Vec<T>);
 1570
 1571struct RegisteredEditPredictionDelegate {
 1572    provider: Arc<dyn EditPredictionDelegateHandle>,
 1573    _subscription: Subscription,
 1574}
 1575
 1576#[derive(Debug, PartialEq, Eq)]
 1577pub struct ActiveDiagnosticGroup {
 1578    pub active_range: Range<Anchor>,
 1579    pub active_message: String,
 1580    pub group_id: usize,
 1581    pub blocks: HashSet<CustomBlockId>,
 1582}
 1583
 1584#[derive(Debug, PartialEq, Eq)]
 1585
 1586pub(crate) enum ActiveDiagnostic {
 1587    None,
 1588    All,
 1589    Group(ActiveDiagnosticGroup),
 1590}
 1591
 1592#[derive(Serialize, Deserialize, Clone, Debug)]
 1593pub struct ClipboardSelection {
 1594    /// The number of bytes in this selection.
 1595    pub len: usize,
 1596    /// Whether this was a full-line selection.
 1597    pub is_entire_line: bool,
 1598    /// The indentation of the first line when this content was originally copied.
 1599    pub first_line_indent: u32,
 1600    #[serde(default)]
 1601    pub file_path: Option<PathBuf>,
 1602    #[serde(default)]
 1603    pub line_range: Option<RangeInclusive<u32>>,
 1604}
 1605
 1606impl ClipboardSelection {
 1607    pub fn for_buffer(
 1608        len: usize,
 1609        is_entire_line: bool,
 1610        range: Range<Point>,
 1611        buffer: &MultiBufferSnapshot,
 1612        project: Option<&Entity<Project>>,
 1613        cx: &App,
 1614    ) -> Self {
 1615        let first_line_indent = buffer
 1616            .indent_size_for_line(MultiBufferRow(range.start.row))
 1617            .len;
 1618
 1619        let file_path = util::maybe!({
 1620            let project = project?.read(cx);
 1621            let file = buffer.file_at(range.start)?;
 1622            let project_path = ProjectPath {
 1623                worktree_id: file.worktree_id(cx),
 1624                path: file.path().clone(),
 1625            };
 1626            project.absolute_path(&project_path, cx)
 1627        });
 1628
 1629        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1630
 1631        Self {
 1632            len,
 1633            is_entire_line,
 1634            first_line_indent,
 1635            file_path,
 1636            line_range,
 1637        }
 1638    }
 1639}
 1640
 1641// selections, scroll behavior, was newest selection reversed
 1642type SelectSyntaxNodeHistoryState = (
 1643    Box<[Selection<MultiBufferOffset>]>,
 1644    SelectSyntaxNodeScrollBehavior,
 1645    bool,
 1646);
 1647
 1648#[derive(Default)]
 1649struct SelectSyntaxNodeHistory {
 1650    stack: Vec<SelectSyntaxNodeHistoryState>,
 1651    // disable temporarily to allow changing selections without losing the stack
 1652    pub disable_clearing: bool,
 1653}
 1654
 1655impl SelectSyntaxNodeHistory {
 1656    pub fn try_clear(&mut self) {
 1657        if !self.disable_clearing {
 1658            self.stack.clear();
 1659        }
 1660    }
 1661
 1662    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1663        self.stack.push(selection);
 1664    }
 1665
 1666    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1667        self.stack.pop()
 1668    }
 1669}
 1670
 1671enum SelectSyntaxNodeScrollBehavior {
 1672    CursorTop,
 1673    FitSelection,
 1674    CursorBottom,
 1675}
 1676
 1677#[derive(Debug)]
 1678pub(crate) struct NavigationData {
 1679    cursor_anchor: Anchor,
 1680    cursor_position: Point,
 1681    scroll_anchor: ScrollAnchor,
 1682    scroll_top_row: u32,
 1683}
 1684
 1685#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1686pub enum GotoDefinitionKind {
 1687    Symbol,
 1688    Declaration,
 1689    Type,
 1690    Implementation,
 1691}
 1692
 1693pub enum FormatTarget {
 1694    Buffers(HashSet<Entity<Buffer>>),
 1695    Ranges(Vec<Range<MultiBufferPoint>>),
 1696}
 1697
 1698pub(crate) struct FocusedBlock {
 1699    id: BlockId,
 1700    focus_handle: WeakFocusHandle,
 1701}
 1702
 1703#[derive(Clone, Debug)]
 1704enum JumpData {
 1705    MultiBufferRow {
 1706        row: MultiBufferRow,
 1707        line_offset_from_top: u32,
 1708    },
 1709    MultiBufferPoint {
 1710        excerpt_id: ExcerptId,
 1711        position: Point,
 1712        anchor: text::Anchor,
 1713        line_offset_from_top: u32,
 1714    },
 1715}
 1716
 1717pub enum MultibufferSelectionMode {
 1718    First,
 1719    All,
 1720}
 1721
 1722#[derive(Clone, Copy, Debug, Default)]
 1723pub struct RewrapOptions {
 1724    pub override_language_settings: bool,
 1725    pub preserve_existing_whitespace: bool,
 1726}
 1727
 1728impl Editor {
 1729    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1730        let buffer = cx.new(|cx| Buffer::local("", cx));
 1731        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1732        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1733    }
 1734
 1735    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1736        let buffer = cx.new(|cx| Buffer::local("", cx));
 1737        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1738        Self::new(EditorMode::full(), buffer, None, window, cx)
 1739    }
 1740
 1741    pub fn auto_height(
 1742        min_lines: usize,
 1743        max_lines: usize,
 1744        window: &mut Window,
 1745        cx: &mut Context<Self>,
 1746    ) -> Self {
 1747        let buffer = cx.new(|cx| Buffer::local("", cx));
 1748        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1749        Self::new(
 1750            EditorMode::AutoHeight {
 1751                min_lines,
 1752                max_lines: Some(max_lines),
 1753            },
 1754            buffer,
 1755            None,
 1756            window,
 1757            cx,
 1758        )
 1759    }
 1760
 1761    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1762    /// The editor grows as tall as needed to fit its content.
 1763    pub fn auto_height_unbounded(
 1764        min_lines: usize,
 1765        window: &mut Window,
 1766        cx: &mut Context<Self>,
 1767    ) -> Self {
 1768        let buffer = cx.new(|cx| Buffer::local("", cx));
 1769        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1770        Self::new(
 1771            EditorMode::AutoHeight {
 1772                min_lines,
 1773                max_lines: None,
 1774            },
 1775            buffer,
 1776            None,
 1777            window,
 1778            cx,
 1779        )
 1780    }
 1781
 1782    pub fn for_buffer(
 1783        buffer: Entity<Buffer>,
 1784        project: Option<Entity<Project>>,
 1785        window: &mut Window,
 1786        cx: &mut Context<Self>,
 1787    ) -> Self {
 1788        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1789        Self::new(EditorMode::full(), buffer, project, window, cx)
 1790    }
 1791
 1792    pub fn for_multibuffer(
 1793        buffer: Entity<MultiBuffer>,
 1794        project: Option<Entity<Project>>,
 1795        window: &mut Window,
 1796        cx: &mut Context<Self>,
 1797    ) -> Self {
 1798        Self::new(EditorMode::full(), buffer, project, window, cx)
 1799    }
 1800
 1801    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1802        let mut clone = Self::new(
 1803            self.mode.clone(),
 1804            self.buffer.clone(),
 1805            self.project.clone(),
 1806            window,
 1807            cx,
 1808        );
 1809        self.display_map.update(cx, |display_map, cx| {
 1810            let snapshot = display_map.snapshot(cx);
 1811            clone.display_map.update(cx, |display_map, cx| {
 1812                display_map.set_state(&snapshot, cx);
 1813            });
 1814        });
 1815        clone.folds_did_change(cx);
 1816        clone.selections.clone_state(&self.selections);
 1817        clone.scroll_manager.clone_state(&self.scroll_manager);
 1818        clone.searchable = self.searchable;
 1819        clone.read_only = self.read_only;
 1820        clone
 1821    }
 1822
 1823    pub fn new(
 1824        mode: EditorMode,
 1825        buffer: Entity<MultiBuffer>,
 1826        project: Option<Entity<Project>>,
 1827        window: &mut Window,
 1828        cx: &mut Context<Self>,
 1829    ) -> Self {
 1830        Editor::new_internal(mode, buffer, project, None, window, cx)
 1831    }
 1832
 1833    pub fn sticky_headers(
 1834        &self,
 1835        style: &EditorStyle,
 1836        cx: &App,
 1837    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1838        let multi_buffer = self.buffer().read(cx);
 1839        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1840        let multi_buffer_visible_start = self
 1841            .scroll_manager
 1842            .anchor()
 1843            .anchor
 1844            .to_point(&multi_buffer_snapshot);
 1845        let max_row = multi_buffer_snapshot.max_point().row;
 1846
 1847        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1848        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1849
 1850        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1851            let outline_items = buffer
 1852                .outline_items_containing(
 1853                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1854                    true,
 1855                    Some(style.syntax.as_ref()),
 1856                )
 1857                .into_iter()
 1858                .map(|outline_item| OutlineItem {
 1859                    depth: outline_item.depth,
 1860                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1861                    source_range_for_text: Anchor::range_in_buffer(
 1862                        *excerpt_id,
 1863                        outline_item.source_range_for_text,
 1864                    ),
 1865                    text: outline_item.text,
 1866                    highlight_ranges: outline_item.highlight_ranges,
 1867                    name_ranges: outline_item.name_ranges,
 1868                    body_range: outline_item
 1869                        .body_range
 1870                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1871                    annotation_range: outline_item
 1872                        .annotation_range
 1873                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1874                });
 1875            return Some(outline_items.collect());
 1876        }
 1877
 1878        None
 1879    }
 1880
 1881    fn new_internal(
 1882        mode: EditorMode,
 1883        multi_buffer: Entity<MultiBuffer>,
 1884        project: Option<Entity<Project>>,
 1885        display_map: Option<Entity<DisplayMap>>,
 1886        window: &mut Window,
 1887        cx: &mut Context<Self>,
 1888    ) -> Self {
 1889        debug_assert!(
 1890            display_map.is_none() || mode.is_minimap(),
 1891            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1892        );
 1893
 1894        let full_mode = mode.is_full();
 1895        let is_minimap = mode.is_minimap();
 1896        let diagnostics_max_severity = if full_mode {
 1897            EditorSettings::get_global(cx)
 1898                .diagnostics_max_severity
 1899                .unwrap_or(DiagnosticSeverity::Hint)
 1900        } else {
 1901            DiagnosticSeverity::Off
 1902        };
 1903        let style = window.text_style();
 1904        let font_size = style.font_size.to_pixels(window.rem_size());
 1905        let editor = cx.entity().downgrade();
 1906        let fold_placeholder = FoldPlaceholder {
 1907            constrain_width: false,
 1908            render: Arc::new(move |fold_id, fold_range, cx| {
 1909                let editor = editor.clone();
 1910                div()
 1911                    .id(fold_id)
 1912                    .bg(cx.theme().colors().ghost_element_background)
 1913                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1914                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1915                    .rounded_xs()
 1916                    .size_full()
 1917                    .cursor_pointer()
 1918                    .child("")
 1919                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1920                    .on_click(move |_, _window, cx| {
 1921                        editor
 1922                            .update(cx, |editor, cx| {
 1923                                editor.unfold_ranges(
 1924                                    &[fold_range.start..fold_range.end],
 1925                                    true,
 1926                                    false,
 1927                                    cx,
 1928                                );
 1929                                cx.stop_propagation();
 1930                            })
 1931                            .ok();
 1932                    })
 1933                    .into_any()
 1934            }),
 1935            merge_adjacent: true,
 1936            ..FoldPlaceholder::default()
 1937        };
 1938        let display_map = display_map.unwrap_or_else(|| {
 1939            cx.new(|cx| {
 1940                DisplayMap::new(
 1941                    multi_buffer.clone(),
 1942                    style.font(),
 1943                    font_size,
 1944                    None,
 1945                    FILE_HEADER_HEIGHT,
 1946                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1947                    fold_placeholder,
 1948                    diagnostics_max_severity,
 1949                    cx,
 1950                )
 1951            })
 1952        });
 1953
 1954        let selections = SelectionsCollection::new();
 1955
 1956        let blink_manager = cx.new(|cx| {
 1957            let mut blink_manager = BlinkManager::new(
 1958                CURSOR_BLINK_INTERVAL,
 1959                |cx| EditorSettings::get_global(cx).cursor_blink,
 1960                cx,
 1961            );
 1962            if is_minimap {
 1963                blink_manager.disable(cx);
 1964            }
 1965            blink_manager
 1966        });
 1967
 1968        let soft_wrap_mode_override =
 1969            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1970
 1971        let mut project_subscriptions = Vec::new();
 1972        if full_mode && let Some(project) = project.as_ref() {
 1973            project_subscriptions.push(cx.subscribe_in(
 1974                project,
 1975                window,
 1976                |editor, _, event, window, cx| match event {
 1977                    project::Event::RefreshCodeLens => {
 1978                        // we always query lens with actions, without storing them, always refreshing them
 1979                    }
 1980                    project::Event::RefreshInlayHints {
 1981                        server_id,
 1982                        request_id,
 1983                    } => {
 1984                        editor.refresh_inlay_hints(
 1985                            InlayHintRefreshReason::RefreshRequested {
 1986                                server_id: *server_id,
 1987                                request_id: *request_id,
 1988                            },
 1989                            cx,
 1990                        );
 1991                    }
 1992                    project::Event::LanguageServerRemoved(..) => {
 1993                        if editor.tasks_update_task.is_none() {
 1994                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1995                        }
 1996                        editor.registered_buffers.clear();
 1997                        editor.register_visible_buffers(cx);
 1998                    }
 1999                    project::Event::LanguageServerAdded(..) => {
 2000                        if editor.tasks_update_task.is_none() {
 2001                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2002                        }
 2003                    }
 2004                    project::Event::SnippetEdit(id, snippet_edits) => {
 2005                        // todo(lw): Non singletons
 2006                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2007                            let snapshot = buffer.read(cx).snapshot();
 2008                            let focus_handle = editor.focus_handle(cx);
 2009                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2010                                for (range, snippet) in snippet_edits {
 2011                                    let buffer_range =
 2012                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2013                                    editor
 2014                                        .insert_snippet(
 2015                                            &[MultiBufferOffset(buffer_range.start)
 2016                                                ..MultiBufferOffset(buffer_range.end)],
 2017                                            snippet.clone(),
 2018                                            window,
 2019                                            cx,
 2020                                        )
 2021                                        .ok();
 2022                                }
 2023                            }
 2024                        }
 2025                    }
 2026                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2027                        let buffer_id = *buffer_id;
 2028                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2029                            editor.register_buffer(buffer_id, cx);
 2030                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2031                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2032                            refresh_linked_ranges(editor, window, cx);
 2033                            editor.refresh_code_actions(window, cx);
 2034                            editor.refresh_document_highlights(cx);
 2035                        }
 2036                    }
 2037
 2038                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2039                        let Some(workspace) = editor.workspace() else {
 2040                            return;
 2041                        };
 2042                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2043                        else {
 2044                            return;
 2045                        };
 2046
 2047                        if active_editor.entity_id() == cx.entity_id() {
 2048                            let entity_id = cx.entity_id();
 2049                            workspace.update(cx, |this, cx| {
 2050                                this.panes_mut()
 2051                                    .iter_mut()
 2052                                    .filter(|pane| pane.entity_id() != entity_id)
 2053                                    .for_each(|p| {
 2054                                        p.update(cx, |pane, _| {
 2055                                            pane.nav_history_mut().rename_item(
 2056                                                entity_id,
 2057                                                project_path.clone(),
 2058                                                abs_path.clone().into(),
 2059                                            );
 2060                                        })
 2061                                    });
 2062                            });
 2063
 2064                            Self::open_transaction_for_hidden_buffers(
 2065                                workspace,
 2066                                transaction.clone(),
 2067                                "Rename".to_string(),
 2068                                window,
 2069                                cx,
 2070                            );
 2071                        }
 2072                    }
 2073
 2074                    project::Event::WorkspaceEditApplied(transaction) => {
 2075                        let Some(workspace) = editor.workspace() else {
 2076                            return;
 2077                        };
 2078                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2079                        else {
 2080                            return;
 2081                        };
 2082
 2083                        if active_editor.entity_id() == cx.entity_id() {
 2084                            Self::open_transaction_for_hidden_buffers(
 2085                                workspace,
 2086                                transaction.clone(),
 2087                                "LSP Edit".to_string(),
 2088                                window,
 2089                                cx,
 2090                            );
 2091                        }
 2092                    }
 2093
 2094                    _ => {}
 2095                },
 2096            ));
 2097            if let Some(task_inventory) = project
 2098                .read(cx)
 2099                .task_store()
 2100                .read(cx)
 2101                .task_inventory()
 2102                .cloned()
 2103            {
 2104                project_subscriptions.push(cx.observe_in(
 2105                    &task_inventory,
 2106                    window,
 2107                    |editor, _, window, cx| {
 2108                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2109                    },
 2110                ));
 2111            };
 2112
 2113            project_subscriptions.push(cx.subscribe_in(
 2114                &project.read(cx).breakpoint_store(),
 2115                window,
 2116                |editor, _, event, window, cx| match event {
 2117                    BreakpointStoreEvent::ClearDebugLines => {
 2118                        editor.clear_row_highlights::<ActiveDebugLine>();
 2119                        editor.refresh_inline_values(cx);
 2120                    }
 2121                    BreakpointStoreEvent::SetDebugLine => {
 2122                        if editor.go_to_active_debug_line(window, cx) {
 2123                            cx.stop_propagation();
 2124                        }
 2125
 2126                        editor.refresh_inline_values(cx);
 2127                    }
 2128                    _ => {}
 2129                },
 2130            ));
 2131            let git_store = project.read(cx).git_store().clone();
 2132            let project = project.clone();
 2133            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2134                if let GitStoreEvent::RepositoryAdded = event {
 2135                    this.load_diff_task = Some(
 2136                        update_uncommitted_diff_for_buffer(
 2137                            cx.entity(),
 2138                            &project,
 2139                            this.buffer.read(cx).all_buffers(),
 2140                            this.buffer.clone(),
 2141                            cx,
 2142                        )
 2143                        .shared(),
 2144                    );
 2145                }
 2146            }));
 2147        }
 2148
 2149        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2150
 2151        let inlay_hint_settings =
 2152            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2153        let focus_handle = cx.focus_handle();
 2154        if !is_minimap {
 2155            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2156                .detach();
 2157            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2158                .detach();
 2159            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2160                .detach();
 2161            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2162                .detach();
 2163            cx.observe_pending_input(window, Self::observe_pending_input)
 2164                .detach();
 2165        }
 2166
 2167        let show_indent_guides =
 2168            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2169                Some(false)
 2170            } else {
 2171                None
 2172            };
 2173
 2174        let breakpoint_store = match (&mode, project.as_ref()) {
 2175            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2176            _ => None,
 2177        };
 2178
 2179        let mut code_action_providers = Vec::new();
 2180        let mut load_uncommitted_diff = None;
 2181        if let Some(project) = project.clone() {
 2182            load_uncommitted_diff = Some(
 2183                update_uncommitted_diff_for_buffer(
 2184                    cx.entity(),
 2185                    &project,
 2186                    multi_buffer.read(cx).all_buffers(),
 2187                    multi_buffer.clone(),
 2188                    cx,
 2189                )
 2190                .shared(),
 2191            );
 2192            code_action_providers.push(Rc::new(project) as Rc<_>);
 2193        }
 2194
 2195        let mut editor = Self {
 2196            focus_handle,
 2197            show_cursor_when_unfocused: false,
 2198            last_focused_descendant: None,
 2199            buffer: multi_buffer.clone(),
 2200            display_map: display_map.clone(),
 2201            placeholder_display_map: None,
 2202            selections,
 2203            scroll_manager: ScrollManager::new(cx),
 2204            columnar_selection_state: None,
 2205            add_selections_state: None,
 2206            select_next_state: None,
 2207            select_prev_state: None,
 2208            selection_history: SelectionHistory::default(),
 2209            defer_selection_effects: false,
 2210            deferred_selection_effects_state: None,
 2211            autoclose_regions: Vec::new(),
 2212            snippet_stack: InvalidationStack::default(),
 2213            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2214            ime_transaction: None,
 2215            active_diagnostics: ActiveDiagnostic::None,
 2216            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2217            inline_diagnostics_update: Task::ready(()),
 2218            inline_diagnostics: Vec::new(),
 2219            soft_wrap_mode_override,
 2220            diagnostics_max_severity,
 2221            hard_wrap: None,
 2222            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2223            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2224            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2225            project,
 2226            blink_manager: blink_manager.clone(),
 2227            show_local_selections: true,
 2228            show_scrollbars: ScrollbarAxes {
 2229                horizontal: full_mode,
 2230                vertical: full_mode,
 2231            },
 2232            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2233            offset_content: !matches!(mode, EditorMode::SingleLine),
 2234            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2235            show_gutter: full_mode,
 2236            show_line_numbers: (!full_mode).then_some(false),
 2237            use_relative_line_numbers: None,
 2238            disable_expand_excerpt_buttons: !full_mode,
 2239            show_git_diff_gutter: None,
 2240            show_code_actions: None,
 2241            show_runnables: None,
 2242            show_breakpoints: None,
 2243            show_wrap_guides: None,
 2244            show_indent_guides,
 2245            buffers_with_disabled_indent_guides: HashSet::default(),
 2246            highlight_order: 0,
 2247            highlighted_rows: HashMap::default(),
 2248            background_highlights: HashMap::default(),
 2249            gutter_highlights: HashMap::default(),
 2250            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2251            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2252            nav_history: None,
 2253            context_menu: RefCell::new(None),
 2254            context_menu_options: None,
 2255            mouse_context_menu: None,
 2256            completion_tasks: Vec::new(),
 2257            inline_blame_popover: None,
 2258            inline_blame_popover_show_task: None,
 2259            signature_help_state: SignatureHelpState::default(),
 2260            auto_signature_help: None,
 2261            find_all_references_task_sources: Vec::new(),
 2262            next_completion_id: 0,
 2263            next_inlay_id: 0,
 2264            code_action_providers,
 2265            available_code_actions: None,
 2266            code_actions_task: None,
 2267            quick_selection_highlight_task: None,
 2268            debounced_selection_highlight_task: None,
 2269            document_highlights_task: None,
 2270            linked_editing_range_task: None,
 2271            pending_rename: None,
 2272            searchable: !is_minimap,
 2273            cursor_shape: EditorSettings::get_global(cx)
 2274                .cursor_shape
 2275                .unwrap_or_default(),
 2276            cursor_offset_on_selection: false,
 2277            current_line_highlight: None,
 2278            autoindent_mode: Some(AutoindentMode::EachLine),
 2279            collapse_matches: false,
 2280            workspace: None,
 2281            input_enabled: !is_minimap,
 2282            use_modal_editing: full_mode,
 2283            read_only: is_minimap,
 2284            use_autoclose: true,
 2285            use_auto_surround: true,
 2286            auto_replace_emoji_shortcode: false,
 2287            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2288            leader_id: None,
 2289            remote_id: None,
 2290            hover_state: HoverState::default(),
 2291            pending_mouse_down: None,
 2292            prev_pressure_stage: None,
 2293            hovered_link_state: None,
 2294            edit_prediction_provider: None,
 2295            active_edit_prediction: None,
 2296            stale_edit_prediction_in_menu: None,
 2297            edit_prediction_preview: EditPredictionPreview::Inactive {
 2298                released_too_fast: false,
 2299            },
 2300            inline_diagnostics_enabled: full_mode,
 2301            diagnostics_enabled: full_mode,
 2302            word_completions_enabled: full_mode,
 2303            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2304            gutter_hovered: false,
 2305            pixel_position_of_newest_cursor: None,
 2306            last_bounds: None,
 2307            last_position_map: None,
 2308            expect_bounds_change: None,
 2309            gutter_dimensions: GutterDimensions::default(),
 2310            style: None,
 2311            show_cursor_names: false,
 2312            hovered_cursors: HashMap::default(),
 2313            next_editor_action_id: EditorActionId::default(),
 2314            editor_actions: Rc::default(),
 2315            edit_predictions_hidden_for_vim_mode: false,
 2316            show_edit_predictions_override: None,
 2317            show_completions_on_input_override: None,
 2318            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2319            edit_prediction_settings: EditPredictionSettings::Disabled,
 2320            edit_prediction_indent_conflict: false,
 2321            edit_prediction_requires_modifier_in_indent_conflict: true,
 2322            custom_context_menu: None,
 2323            show_git_blame_gutter: false,
 2324            show_git_blame_inline: false,
 2325            show_selection_menu: None,
 2326            show_git_blame_inline_delay_task: None,
 2327            git_blame_inline_enabled: full_mode
 2328                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2329            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2330            buffer_serialization: is_minimap.not().then(|| {
 2331                BufferSerialization::new(
 2332                    ProjectSettings::get_global(cx)
 2333                        .session
 2334                        .restore_unsaved_buffers,
 2335                )
 2336            }),
 2337            blame: None,
 2338            blame_subscription: None,
 2339            tasks: BTreeMap::default(),
 2340
 2341            breakpoint_store,
 2342            gutter_breakpoint_indicator: (None, None),
 2343            hovered_diff_hunk_row: None,
 2344            _subscriptions: (!is_minimap)
 2345                .then(|| {
 2346                    vec![
 2347                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2348                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2349                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2350                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2351                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2352                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2353                        cx.observe_window_activation(window, |editor, window, cx| {
 2354                            let active = window.is_window_active();
 2355                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2356                                if active {
 2357                                    blink_manager.enable(cx);
 2358                                } else {
 2359                                    blink_manager.disable(cx);
 2360                                }
 2361                            });
 2362                            if active {
 2363                                editor.show_mouse_cursor(cx);
 2364                            }
 2365                        }),
 2366                    ]
 2367                })
 2368                .unwrap_or_default(),
 2369            tasks_update_task: None,
 2370            pull_diagnostics_task: Task::ready(()),
 2371            pull_diagnostics_background_task: Task::ready(()),
 2372            colors: None,
 2373            refresh_colors_task: Task::ready(()),
 2374            inlay_hints: None,
 2375            next_color_inlay_id: 0,
 2376            post_scroll_update: Task::ready(()),
 2377            linked_edit_ranges: Default::default(),
 2378            in_project_search: false,
 2379            previous_search_ranges: None,
 2380            breadcrumb_header: None,
 2381            focused_block: None,
 2382            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2383            addons: HashMap::default(),
 2384            registered_buffers: HashMap::default(),
 2385            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2386            selection_mark_mode: false,
 2387            toggle_fold_multiple_buffers: Task::ready(()),
 2388            serialize_selections: Task::ready(()),
 2389            serialize_folds: Task::ready(()),
 2390            text_style_refinement: None,
 2391            load_diff_task: load_uncommitted_diff,
 2392            temporary_diff_override: false,
 2393            mouse_cursor_hidden: false,
 2394            minimap: None,
 2395            hide_mouse_mode: EditorSettings::get_global(cx)
 2396                .hide_mouse
 2397                .unwrap_or_default(),
 2398            change_list: ChangeList::new(),
 2399            mode,
 2400            selection_drag_state: SelectionDragState::None,
 2401            folding_newlines: Task::ready(()),
 2402            lookup_key: None,
 2403            select_next_is_case_sensitive: None,
 2404            applicable_language_settings: HashMap::default(),
 2405            accent_data: None,
 2406            fetched_tree_sitter_chunks: HashMap::default(),
 2407            use_base_text_line_numbers: false,
 2408        };
 2409
 2410        if is_minimap {
 2411            return editor;
 2412        }
 2413
 2414        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2415        editor.accent_data = editor.fetch_accent_data(cx);
 2416
 2417        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2418            editor
 2419                ._subscriptions
 2420                .push(cx.observe(breakpoints, |_, _, cx| {
 2421                    cx.notify();
 2422                }));
 2423        }
 2424        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2425        editor._subscriptions.extend(project_subscriptions);
 2426
 2427        editor._subscriptions.push(cx.subscribe_in(
 2428            &cx.entity(),
 2429            window,
 2430            |editor, _, e: &EditorEvent, window, cx| match e {
 2431                EditorEvent::ScrollPositionChanged { local, .. } => {
 2432                    if *local {
 2433                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2434                        editor.inline_blame_popover.take();
 2435                        let new_anchor = editor.scroll_manager.anchor();
 2436                        let snapshot = editor.snapshot(window, cx);
 2437                        editor.update_restoration_data(cx, move |data| {
 2438                            data.scroll_position = (
 2439                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2440                                new_anchor.offset,
 2441                            );
 2442                        });
 2443
 2444                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2445                            cx.background_executor()
 2446                                .timer(Duration::from_millis(50))
 2447                                .await;
 2448                            editor
 2449                                .update_in(cx, |editor, window, cx| {
 2450                                    editor.register_visible_buffers(cx);
 2451                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2452                                    editor.refresh_inlay_hints(
 2453                                        InlayHintRefreshReason::NewLinesShown,
 2454                                        cx,
 2455                                    );
 2456                                    editor.colorize_brackets(false, cx);
 2457                                })
 2458                                .ok();
 2459                        });
 2460                    }
 2461                }
 2462                EditorEvent::Edited { .. } => {
 2463                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2464                        .map(|vim_mode| vim_mode.0)
 2465                        .unwrap_or(false);
 2466                    if !vim_mode {
 2467                        let display_map = editor.display_snapshot(cx);
 2468                        let selections = editor.selections.all_adjusted_display(&display_map);
 2469                        let pop_state = editor
 2470                            .change_list
 2471                            .last()
 2472                            .map(|previous| {
 2473                                previous.len() == selections.len()
 2474                                    && previous.iter().enumerate().all(|(ix, p)| {
 2475                                        p.to_display_point(&display_map).row()
 2476                                            == selections[ix].head().row()
 2477                                    })
 2478                            })
 2479                            .unwrap_or(false);
 2480                        let new_positions = selections
 2481                            .into_iter()
 2482                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2483                            .collect();
 2484                        editor
 2485                            .change_list
 2486                            .push_to_change_list(pop_state, new_positions);
 2487                    }
 2488                }
 2489                _ => (),
 2490            },
 2491        ));
 2492
 2493        if let Some(dap_store) = editor
 2494            .project
 2495            .as_ref()
 2496            .map(|project| project.read(cx).dap_store())
 2497        {
 2498            let weak_editor = cx.weak_entity();
 2499
 2500            editor
 2501                ._subscriptions
 2502                .push(
 2503                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2504                        let session_entity = cx.entity();
 2505                        weak_editor
 2506                            .update(cx, |editor, cx| {
 2507                                editor._subscriptions.push(
 2508                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2509                                );
 2510                            })
 2511                            .ok();
 2512                    }),
 2513                );
 2514
 2515            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2516                editor
 2517                    ._subscriptions
 2518                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2519            }
 2520        }
 2521
 2522        // skip adding the initial selection to selection history
 2523        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2524        editor.end_selection(window, cx);
 2525        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2526
 2527        editor.scroll_manager.show_scrollbars(window, cx);
 2528        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2529
 2530        if full_mode {
 2531            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2532            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2533
 2534            if editor.git_blame_inline_enabled {
 2535                editor.start_git_blame_inline(false, window, cx);
 2536            }
 2537
 2538            editor.go_to_active_debug_line(window, cx);
 2539
 2540            editor.minimap =
 2541                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2542            editor.colors = Some(LspColorData::new(cx));
 2543            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2544
 2545            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2546                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2547            }
 2548            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2549        }
 2550
 2551        editor
 2552    }
 2553
 2554    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2555        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2556    }
 2557
 2558    pub fn deploy_mouse_context_menu(
 2559        &mut self,
 2560        position: gpui::Point<Pixels>,
 2561        context_menu: Entity<ContextMenu>,
 2562        window: &mut Window,
 2563        cx: &mut Context<Self>,
 2564    ) {
 2565        self.mouse_context_menu = Some(MouseContextMenu::new(
 2566            self,
 2567            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2568            context_menu,
 2569            window,
 2570            cx,
 2571        ));
 2572    }
 2573
 2574    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2575        self.mouse_context_menu
 2576            .as_ref()
 2577            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2578    }
 2579
 2580    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2581        if self
 2582            .selections
 2583            .pending_anchor()
 2584            .is_some_and(|pending_selection| {
 2585                let snapshot = self.buffer().read(cx).snapshot(cx);
 2586                pending_selection.range().includes(range, &snapshot)
 2587            })
 2588        {
 2589            return true;
 2590        }
 2591
 2592        self.selections
 2593            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2594            .into_iter()
 2595            .any(|selection| {
 2596                // This is needed to cover a corner case, if we just check for an existing
 2597                // selection in the fold range, having a cursor at the start of the fold
 2598                // marks it as selected. Non-empty selections don't cause this.
 2599                let length = selection.end - selection.start;
 2600                length > 0
 2601            })
 2602    }
 2603
 2604    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2605        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2606    }
 2607
 2608    fn key_context_internal(
 2609        &self,
 2610        has_active_edit_prediction: bool,
 2611        window: &mut Window,
 2612        cx: &mut App,
 2613    ) -> KeyContext {
 2614        let mut key_context = KeyContext::new_with_defaults();
 2615        key_context.add("Editor");
 2616        let mode = match self.mode {
 2617            EditorMode::SingleLine => "single_line",
 2618            EditorMode::AutoHeight { .. } => "auto_height",
 2619            EditorMode::Minimap { .. } => "minimap",
 2620            EditorMode::Full { .. } => "full",
 2621        };
 2622
 2623        if EditorSettings::jupyter_enabled(cx) {
 2624            key_context.add("jupyter");
 2625        }
 2626
 2627        key_context.set("mode", mode);
 2628        if self.pending_rename.is_some() {
 2629            key_context.add("renaming");
 2630        }
 2631
 2632        if let Some(snippet_stack) = self.snippet_stack.last() {
 2633            key_context.add("in_snippet");
 2634
 2635            if snippet_stack.active_index > 0 {
 2636                key_context.add("has_previous_tabstop");
 2637            }
 2638
 2639            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2640                key_context.add("has_next_tabstop");
 2641            }
 2642        }
 2643
 2644        match self.context_menu.borrow().as_ref() {
 2645            Some(CodeContextMenu::Completions(menu)) => {
 2646                if menu.visible() {
 2647                    key_context.add("menu");
 2648                    key_context.add("showing_completions");
 2649                }
 2650            }
 2651            Some(CodeContextMenu::CodeActions(menu)) => {
 2652                if menu.visible() {
 2653                    key_context.add("menu");
 2654                    key_context.add("showing_code_actions")
 2655                }
 2656            }
 2657            None => {}
 2658        }
 2659
 2660        if self.signature_help_state.has_multiple_signatures() {
 2661            key_context.add("showing_signature_help");
 2662        }
 2663
 2664        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2665        if !self.focus_handle(cx).contains_focused(window, cx)
 2666            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2667        {
 2668            for addon in self.addons.values() {
 2669                addon.extend_key_context(&mut key_context, cx)
 2670            }
 2671        }
 2672
 2673        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2674            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2675                Some(
 2676                    file.full_path(cx)
 2677                        .extension()?
 2678                        .to_string_lossy()
 2679                        .into_owned(),
 2680                )
 2681            }) {
 2682                key_context.set("extension", extension);
 2683            }
 2684        } else {
 2685            key_context.add("multibuffer");
 2686        }
 2687
 2688        if has_active_edit_prediction {
 2689            if self.edit_prediction_in_conflict() {
 2690                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2691            } else {
 2692                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2693                key_context.add("copilot_suggestion");
 2694            }
 2695        }
 2696
 2697        if self.selection_mark_mode {
 2698            key_context.add("selection_mode");
 2699        }
 2700
 2701        let disjoint = self.selections.disjoint_anchors();
 2702        let snapshot = self.snapshot(window, cx);
 2703        let snapshot = snapshot.buffer_snapshot();
 2704        if self.mode == EditorMode::SingleLine
 2705            && let [selection] = disjoint
 2706            && selection.start == selection.end
 2707            && selection.end.to_offset(snapshot) == snapshot.len()
 2708        {
 2709            key_context.add("end_of_input");
 2710        }
 2711
 2712        if self.has_any_expanded_diff_hunks(cx) {
 2713            key_context.add("diffs_expanded");
 2714        }
 2715
 2716        key_context
 2717    }
 2718
 2719    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2720        self.last_bounds.as_ref()
 2721    }
 2722
 2723    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2724        if self.mouse_cursor_hidden {
 2725            self.mouse_cursor_hidden = false;
 2726            cx.notify();
 2727        }
 2728    }
 2729
 2730    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2731        let hide_mouse_cursor = match origin {
 2732            HideMouseCursorOrigin::TypingAction => {
 2733                matches!(
 2734                    self.hide_mouse_mode,
 2735                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2736                )
 2737            }
 2738            HideMouseCursorOrigin::MovementAction => {
 2739                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2740            }
 2741        };
 2742        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2743            self.mouse_cursor_hidden = hide_mouse_cursor;
 2744            cx.notify();
 2745        }
 2746    }
 2747
 2748    pub fn edit_prediction_in_conflict(&self) -> bool {
 2749        if !self.show_edit_predictions_in_menu() {
 2750            return false;
 2751        }
 2752
 2753        let showing_completions = self
 2754            .context_menu
 2755            .borrow()
 2756            .as_ref()
 2757            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2758
 2759        showing_completions
 2760            || self.edit_prediction_requires_modifier()
 2761            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2762            // bindings to insert tab characters.
 2763            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2764    }
 2765
 2766    pub fn accept_edit_prediction_keybind(
 2767        &self,
 2768        granularity: EditPredictionGranularity,
 2769        window: &mut Window,
 2770        cx: &mut App,
 2771    ) -> AcceptEditPredictionBinding {
 2772        let key_context = self.key_context_internal(true, window, cx);
 2773        let in_conflict = self.edit_prediction_in_conflict();
 2774
 2775        let bindings =
 2776            match granularity {
 2777                EditPredictionGranularity::Word => window
 2778                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2779                EditPredictionGranularity::Line => window
 2780                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2781                EditPredictionGranularity::Full => {
 2782                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2783                }
 2784            };
 2785
 2786        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2787            !in_conflict
 2788                || binding
 2789                    .keystrokes()
 2790                    .first()
 2791                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2792        }))
 2793    }
 2794
 2795    pub fn new_file(
 2796        workspace: &mut Workspace,
 2797        _: &workspace::NewFile,
 2798        window: &mut Window,
 2799        cx: &mut Context<Workspace>,
 2800    ) {
 2801        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2802            "Failed to create buffer",
 2803            window,
 2804            cx,
 2805            |e, _, _| match e.error_code() {
 2806                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2807                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2808                e.error_tag("required").unwrap_or("the latest version")
 2809            )),
 2810                _ => None,
 2811            },
 2812        );
 2813    }
 2814
 2815    pub fn new_in_workspace(
 2816        workspace: &mut Workspace,
 2817        window: &mut Window,
 2818        cx: &mut Context<Workspace>,
 2819    ) -> Task<Result<Entity<Editor>>> {
 2820        let project = workspace.project().clone();
 2821        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2822
 2823        cx.spawn_in(window, async move |workspace, cx| {
 2824            let buffer = create.await?;
 2825            workspace.update_in(cx, |workspace, window, cx| {
 2826                let editor =
 2827                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2828                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2829                editor
 2830            })
 2831        })
 2832    }
 2833
 2834    fn new_file_vertical(
 2835        workspace: &mut Workspace,
 2836        _: &workspace::NewFileSplitVertical,
 2837        window: &mut Window,
 2838        cx: &mut Context<Workspace>,
 2839    ) {
 2840        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2841    }
 2842
 2843    fn new_file_horizontal(
 2844        workspace: &mut Workspace,
 2845        _: &workspace::NewFileSplitHorizontal,
 2846        window: &mut Window,
 2847        cx: &mut Context<Workspace>,
 2848    ) {
 2849        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2850    }
 2851
 2852    fn new_file_split(
 2853        workspace: &mut Workspace,
 2854        action: &workspace::NewFileSplit,
 2855        window: &mut Window,
 2856        cx: &mut Context<Workspace>,
 2857    ) {
 2858        Self::new_file_in_direction(workspace, action.0, window, cx)
 2859    }
 2860
 2861    fn new_file_in_direction(
 2862        workspace: &mut Workspace,
 2863        direction: SplitDirection,
 2864        window: &mut Window,
 2865        cx: &mut Context<Workspace>,
 2866    ) {
 2867        let project = workspace.project().clone();
 2868        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2869
 2870        cx.spawn_in(window, async move |workspace, cx| {
 2871            let buffer = create.await?;
 2872            workspace.update_in(cx, move |workspace, window, cx| {
 2873                workspace.split_item(
 2874                    direction,
 2875                    Box::new(
 2876                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2877                    ),
 2878                    window,
 2879                    cx,
 2880                )
 2881            })?;
 2882            anyhow::Ok(())
 2883        })
 2884        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2885            match e.error_code() {
 2886                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2887                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2888                e.error_tag("required").unwrap_or("the latest version")
 2889            )),
 2890                _ => None,
 2891            }
 2892        });
 2893    }
 2894
 2895    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2896        self.leader_id
 2897    }
 2898
 2899    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2900        &self.buffer
 2901    }
 2902
 2903    pub fn project(&self) -> Option<&Entity<Project>> {
 2904        self.project.as_ref()
 2905    }
 2906
 2907    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2908        self.workspace.as_ref()?.0.upgrade()
 2909    }
 2910
 2911    /// Returns the workspace serialization ID if this editor should be serialized.
 2912    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2913        self.workspace
 2914            .as_ref()
 2915            .filter(|_| self.should_serialize_buffer())
 2916            .and_then(|workspace| workspace.1)
 2917    }
 2918
 2919    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2920        self.buffer().read(cx).title(cx)
 2921    }
 2922
 2923    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2924        let git_blame_gutter_max_author_length = self
 2925            .render_git_blame_gutter(cx)
 2926            .then(|| {
 2927                if let Some(blame) = self.blame.as_ref() {
 2928                    let max_author_length =
 2929                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2930                    Some(max_author_length)
 2931                } else {
 2932                    None
 2933                }
 2934            })
 2935            .flatten();
 2936
 2937        EditorSnapshot {
 2938            mode: self.mode.clone(),
 2939            show_gutter: self.show_gutter,
 2940            offset_content: self.offset_content,
 2941            show_line_numbers: self.show_line_numbers,
 2942            show_git_diff_gutter: self.show_git_diff_gutter,
 2943            show_code_actions: self.show_code_actions,
 2944            show_runnables: self.show_runnables,
 2945            show_breakpoints: self.show_breakpoints,
 2946            git_blame_gutter_max_author_length,
 2947            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2948            placeholder_display_snapshot: self
 2949                .placeholder_display_map
 2950                .as_ref()
 2951                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2952            scroll_anchor: self.scroll_manager.anchor(),
 2953            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2954            is_focused: self.focus_handle.is_focused(window),
 2955            current_line_highlight: self
 2956                .current_line_highlight
 2957                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2958            gutter_hovered: self.gutter_hovered,
 2959        }
 2960    }
 2961
 2962    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2963        self.buffer.read(cx).language_at(point, cx)
 2964    }
 2965
 2966    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2967        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2968    }
 2969
 2970    pub fn active_excerpt(
 2971        &self,
 2972        cx: &App,
 2973    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2974        self.buffer
 2975            .read(cx)
 2976            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2977    }
 2978
 2979    pub fn mode(&self) -> &EditorMode {
 2980        &self.mode
 2981    }
 2982
 2983    pub fn set_mode(&mut self, mode: EditorMode) {
 2984        self.mode = mode;
 2985    }
 2986
 2987    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2988        self.collaboration_hub.as_deref()
 2989    }
 2990
 2991    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2992        self.collaboration_hub = Some(hub);
 2993    }
 2994
 2995    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2996        self.in_project_search = in_project_search;
 2997    }
 2998
 2999    pub fn set_custom_context_menu(
 3000        &mut self,
 3001        f: impl 'static
 3002        + Fn(
 3003            &mut Self,
 3004            DisplayPoint,
 3005            &mut Window,
 3006            &mut Context<Self>,
 3007        ) -> Option<Entity<ui::ContextMenu>>,
 3008    ) {
 3009        self.custom_context_menu = Some(Box::new(f))
 3010    }
 3011
 3012    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3013        self.completion_provider = provider;
 3014    }
 3015
 3016    #[cfg(any(test, feature = "test-support"))]
 3017    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3018        self.completion_provider.clone()
 3019    }
 3020
 3021    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3022        self.semantics_provider.clone()
 3023    }
 3024
 3025    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3026        self.semantics_provider = provider;
 3027    }
 3028
 3029    pub fn set_edit_prediction_provider<T>(
 3030        &mut self,
 3031        provider: Option<Entity<T>>,
 3032        window: &mut Window,
 3033        cx: &mut Context<Self>,
 3034    ) where
 3035        T: EditPredictionDelegate,
 3036    {
 3037        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3038            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3039                if this.focus_handle.is_focused(window) {
 3040                    this.update_visible_edit_prediction(window, cx);
 3041                }
 3042            }),
 3043            provider: Arc::new(provider),
 3044        });
 3045        self.update_edit_prediction_settings(cx);
 3046        self.refresh_edit_prediction(false, false, window, cx);
 3047    }
 3048
 3049    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3050        self.placeholder_display_map
 3051            .as_ref()
 3052            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3053    }
 3054
 3055    pub fn set_placeholder_text(
 3056        &mut self,
 3057        placeholder_text: &str,
 3058        window: &mut Window,
 3059        cx: &mut Context<Self>,
 3060    ) {
 3061        let multibuffer = cx
 3062            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3063
 3064        let style = window.text_style();
 3065
 3066        self.placeholder_display_map = Some(cx.new(|cx| {
 3067            DisplayMap::new(
 3068                multibuffer,
 3069                style.font(),
 3070                style.font_size.to_pixels(window.rem_size()),
 3071                None,
 3072                FILE_HEADER_HEIGHT,
 3073                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3074                Default::default(),
 3075                DiagnosticSeverity::Off,
 3076                cx,
 3077            )
 3078        }));
 3079        cx.notify();
 3080    }
 3081
 3082    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3083        self.cursor_shape = cursor_shape;
 3084
 3085        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3086        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3087
 3088        cx.notify();
 3089    }
 3090
 3091    pub fn cursor_shape(&self) -> CursorShape {
 3092        self.cursor_shape
 3093    }
 3094
 3095    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3096        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3097    }
 3098
 3099    pub fn set_current_line_highlight(
 3100        &mut self,
 3101        current_line_highlight: Option<CurrentLineHighlight>,
 3102    ) {
 3103        self.current_line_highlight = current_line_highlight;
 3104    }
 3105
 3106    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3107        self.collapse_matches = collapse_matches;
 3108    }
 3109
 3110    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3111        if self.collapse_matches {
 3112            return range.start..range.start;
 3113        }
 3114        range.clone()
 3115    }
 3116
 3117    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3118        self.display_map.read(cx).clip_at_line_ends
 3119    }
 3120
 3121    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3122        if self.display_map.read(cx).clip_at_line_ends != clip {
 3123            self.display_map
 3124                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3125        }
 3126    }
 3127
 3128    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3129        self.input_enabled = input_enabled;
 3130    }
 3131
 3132    pub fn set_edit_predictions_hidden_for_vim_mode(
 3133        &mut self,
 3134        hidden: bool,
 3135        window: &mut Window,
 3136        cx: &mut Context<Self>,
 3137    ) {
 3138        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3139            self.edit_predictions_hidden_for_vim_mode = hidden;
 3140            if hidden {
 3141                self.update_visible_edit_prediction(window, cx);
 3142            } else {
 3143                self.refresh_edit_prediction(true, false, window, cx);
 3144            }
 3145        }
 3146    }
 3147
 3148    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3149        self.menu_edit_predictions_policy = value;
 3150    }
 3151
 3152    pub fn set_autoindent(&mut self, autoindent: bool) {
 3153        if autoindent {
 3154            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3155        } else {
 3156            self.autoindent_mode = None;
 3157        }
 3158    }
 3159
 3160    pub fn read_only(&self, cx: &App) -> bool {
 3161        self.read_only || self.buffer.read(cx).read_only()
 3162    }
 3163
 3164    pub fn set_read_only(&mut self, read_only: bool) {
 3165        self.read_only = read_only;
 3166    }
 3167
 3168    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3169        self.use_autoclose = autoclose;
 3170    }
 3171
 3172    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3173        self.use_auto_surround = auto_surround;
 3174    }
 3175
 3176    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3177        self.auto_replace_emoji_shortcode = auto_replace;
 3178    }
 3179
 3180    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3181        self.buffer_serialization = should_serialize.then(|| {
 3182            BufferSerialization::new(
 3183                ProjectSettings::get_global(cx)
 3184                    .session
 3185                    .restore_unsaved_buffers,
 3186            )
 3187        })
 3188    }
 3189
 3190    fn should_serialize_buffer(&self) -> bool {
 3191        self.buffer_serialization.is_some()
 3192    }
 3193
 3194    pub fn toggle_edit_predictions(
 3195        &mut self,
 3196        _: &ToggleEditPrediction,
 3197        window: &mut Window,
 3198        cx: &mut Context<Self>,
 3199    ) {
 3200        if self.show_edit_predictions_override.is_some() {
 3201            self.set_show_edit_predictions(None, window, cx);
 3202        } else {
 3203            let show_edit_predictions = !self.edit_predictions_enabled();
 3204            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3205        }
 3206    }
 3207
 3208    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3209        self.show_completions_on_input_override = show_completions_on_input;
 3210    }
 3211
 3212    pub fn set_show_edit_predictions(
 3213        &mut self,
 3214        show_edit_predictions: Option<bool>,
 3215        window: &mut Window,
 3216        cx: &mut Context<Self>,
 3217    ) {
 3218        self.show_edit_predictions_override = show_edit_predictions;
 3219        self.update_edit_prediction_settings(cx);
 3220
 3221        if let Some(false) = show_edit_predictions {
 3222            self.discard_edit_prediction(false, cx);
 3223        } else {
 3224            self.refresh_edit_prediction(false, true, window, cx);
 3225        }
 3226    }
 3227
 3228    fn edit_predictions_disabled_in_scope(
 3229        &self,
 3230        buffer: &Entity<Buffer>,
 3231        buffer_position: language::Anchor,
 3232        cx: &App,
 3233    ) -> bool {
 3234        let snapshot = buffer.read(cx).snapshot();
 3235        let settings = snapshot.settings_at(buffer_position, cx);
 3236
 3237        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3238            return false;
 3239        };
 3240
 3241        scope.override_name().is_some_and(|scope_name| {
 3242            settings
 3243                .edit_predictions_disabled_in
 3244                .iter()
 3245                .any(|s| s == scope_name)
 3246        })
 3247    }
 3248
 3249    pub fn set_use_modal_editing(&mut self, to: bool) {
 3250        self.use_modal_editing = to;
 3251    }
 3252
 3253    pub fn use_modal_editing(&self) -> bool {
 3254        self.use_modal_editing
 3255    }
 3256
 3257    fn selections_did_change(
 3258        &mut self,
 3259        local: bool,
 3260        old_cursor_position: &Anchor,
 3261        effects: SelectionEffects,
 3262        window: &mut Window,
 3263        cx: &mut Context<Self>,
 3264    ) {
 3265        window.invalidate_character_coordinates();
 3266
 3267        // Copy selections to primary selection buffer
 3268        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3269        if local {
 3270            let selections = self
 3271                .selections
 3272                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3273            let buffer_handle = self.buffer.read(cx).read(cx);
 3274
 3275            let mut text = String::new();
 3276            for (index, selection) in selections.iter().enumerate() {
 3277                let text_for_selection = buffer_handle
 3278                    .text_for_range(selection.start..selection.end)
 3279                    .collect::<String>();
 3280
 3281                text.push_str(&text_for_selection);
 3282                if index != selections.len() - 1 {
 3283                    text.push('\n');
 3284                }
 3285            }
 3286
 3287            if !text.is_empty() {
 3288                cx.write_to_primary(ClipboardItem::new_string(text));
 3289            }
 3290        }
 3291
 3292        let selection_anchors = self.selections.disjoint_anchors_arc();
 3293
 3294        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3295            self.buffer.update(cx, |buffer, cx| {
 3296                buffer.set_active_selections(
 3297                    &selection_anchors,
 3298                    self.selections.line_mode(),
 3299                    self.cursor_shape,
 3300                    cx,
 3301                )
 3302            });
 3303        }
 3304        let display_map = self
 3305            .display_map
 3306            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3307        let buffer = display_map.buffer_snapshot();
 3308        if self.selections.count() == 1 {
 3309            self.add_selections_state = None;
 3310        }
 3311        self.select_next_state = None;
 3312        self.select_prev_state = None;
 3313        self.select_syntax_node_history.try_clear();
 3314        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3315        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3316        self.take_rename(false, window, cx);
 3317
 3318        let newest_selection = self.selections.newest_anchor();
 3319        let new_cursor_position = newest_selection.head();
 3320        let selection_start = newest_selection.start;
 3321
 3322        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3323            self.push_to_nav_history(
 3324                *old_cursor_position,
 3325                Some(new_cursor_position.to_point(buffer)),
 3326                false,
 3327                effects.nav_history == Some(true),
 3328                cx,
 3329            );
 3330        }
 3331
 3332        if local {
 3333            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3334                self.register_buffer(buffer_id, cx);
 3335            }
 3336
 3337            let mut context_menu = self.context_menu.borrow_mut();
 3338            let completion_menu = match context_menu.as_ref() {
 3339                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3340                Some(CodeContextMenu::CodeActions(_)) => {
 3341                    *context_menu = None;
 3342                    None
 3343                }
 3344                None => None,
 3345            };
 3346            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3347            drop(context_menu);
 3348
 3349            if effects.completions
 3350                && let Some(completion_position) = completion_position
 3351            {
 3352                let start_offset = selection_start.to_offset(buffer);
 3353                let position_matches = start_offset == completion_position.to_offset(buffer);
 3354                let continue_showing = if let Some((snap, ..)) =
 3355                    buffer.point_to_buffer_offset(completion_position)
 3356                    && !snap.capability.editable()
 3357                {
 3358                    false
 3359                } else if position_matches {
 3360                    if self.snippet_stack.is_empty() {
 3361                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3362                            == Some(CharKind::Word)
 3363                    } else {
 3364                        // Snippet choices can be shown even when the cursor is in whitespace.
 3365                        // Dismissing the menu with actions like backspace is handled by
 3366                        // invalidation regions.
 3367                        true
 3368                    }
 3369                } else {
 3370                    false
 3371                };
 3372
 3373                if continue_showing {
 3374                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3375                } else {
 3376                    self.hide_context_menu(window, cx);
 3377                }
 3378            }
 3379
 3380            hide_hover(self, cx);
 3381
 3382            if old_cursor_position.to_display_point(&display_map).row()
 3383                != new_cursor_position.to_display_point(&display_map).row()
 3384            {
 3385                self.available_code_actions.take();
 3386            }
 3387            self.refresh_code_actions(window, cx);
 3388            self.refresh_document_highlights(cx);
 3389            refresh_linked_ranges(self, window, cx);
 3390
 3391            self.refresh_selected_text_highlights(false, window, cx);
 3392            self.refresh_matching_bracket_highlights(window, cx);
 3393            self.update_visible_edit_prediction(window, cx);
 3394            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3395            self.inline_blame_popover.take();
 3396            if self.git_blame_inline_enabled {
 3397                self.start_inline_blame_timer(window, cx);
 3398            }
 3399        }
 3400
 3401        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3402        cx.emit(EditorEvent::SelectionsChanged { local });
 3403
 3404        let selections = &self.selections.disjoint_anchors_arc();
 3405        if selections.len() == 1 {
 3406            cx.emit(SearchEvent::ActiveMatchChanged)
 3407        }
 3408        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3409            let inmemory_selections = selections
 3410                .iter()
 3411                .map(|s| {
 3412                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3413                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3414                })
 3415                .collect();
 3416            self.update_restoration_data(cx, |data| {
 3417                data.selections = inmemory_selections;
 3418            });
 3419
 3420            if WorkspaceSettings::get(None, cx).restore_on_startup
 3421                != RestoreOnStartupBehavior::EmptyTab
 3422                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3423            {
 3424                let snapshot = self.buffer().read(cx).snapshot(cx);
 3425                let selections = selections.clone();
 3426                let background_executor = cx.background_executor().clone();
 3427                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3428                self.serialize_selections = cx.background_spawn(async move {
 3429                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3430                    let db_selections = selections
 3431                        .iter()
 3432                        .map(|selection| {
 3433                            (
 3434                                selection.start.to_offset(&snapshot).0,
 3435                                selection.end.to_offset(&snapshot).0,
 3436                            )
 3437                        })
 3438                        .collect();
 3439
 3440                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3441                        .await
 3442                        .with_context(|| {
 3443                            format!(
 3444                                "persisting editor selections for editor {editor_id}, \
 3445                                workspace {workspace_id:?}"
 3446                            )
 3447                        })
 3448                        .log_err();
 3449                });
 3450            }
 3451        }
 3452
 3453        cx.notify();
 3454    }
 3455
 3456    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3457        use text::ToOffset as _;
 3458        use text::ToPoint as _;
 3459
 3460        if self.mode.is_minimap()
 3461            || WorkspaceSettings::get(None, cx).restore_on_startup
 3462                == RestoreOnStartupBehavior::EmptyTab
 3463        {
 3464            return;
 3465        }
 3466
 3467        if !self.buffer().read(cx).is_singleton() {
 3468            return;
 3469        }
 3470
 3471        let display_snapshot = self
 3472            .display_map
 3473            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3474        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3475            return;
 3476        };
 3477        let inmemory_folds = display_snapshot
 3478            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3479            .map(|fold| {
 3480                fold.range.start.text_anchor.to_point(&snapshot)
 3481                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3482            })
 3483            .collect();
 3484        self.update_restoration_data(cx, |data| {
 3485            data.folds = inmemory_folds;
 3486        });
 3487
 3488        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3489            return;
 3490        };
 3491        let background_executor = cx.background_executor().clone();
 3492        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3493        let db_folds = display_snapshot
 3494            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3495            .map(|fold| {
 3496                (
 3497                    fold.range.start.text_anchor.to_offset(&snapshot),
 3498                    fold.range.end.text_anchor.to_offset(&snapshot),
 3499                )
 3500            })
 3501            .collect();
 3502        self.serialize_folds = cx.background_spawn(async move {
 3503            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3504            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3505                .await
 3506                .with_context(|| {
 3507                    format!(
 3508                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3509                    )
 3510                })
 3511                .log_err();
 3512        });
 3513    }
 3514
 3515    pub fn sync_selections(
 3516        &mut self,
 3517        other: Entity<Editor>,
 3518        cx: &mut Context<Self>,
 3519    ) -> gpui::Subscription {
 3520        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3521        if !other_selections.is_empty() {
 3522            self.selections
 3523                .change_with(&self.display_snapshot(cx), |selections| {
 3524                    selections.select_anchors(other_selections);
 3525                });
 3526        }
 3527
 3528        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3529            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3530                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3531                if other_selections.is_empty() {
 3532                    return;
 3533                }
 3534                let snapshot = this.display_snapshot(cx);
 3535                this.selections.change_with(&snapshot, |selections| {
 3536                    selections.select_anchors(other_selections);
 3537                });
 3538            }
 3539        });
 3540
 3541        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3542            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3543                let these_selections = this.selections.disjoint_anchors().to_vec();
 3544                if these_selections.is_empty() {
 3545                    return;
 3546                }
 3547                other.update(cx, |other_editor, cx| {
 3548                    let snapshot = other_editor.display_snapshot(cx);
 3549                    other_editor
 3550                        .selections
 3551                        .change_with(&snapshot, |selections| {
 3552                            selections.select_anchors(these_selections);
 3553                        })
 3554                });
 3555            }
 3556        });
 3557
 3558        Subscription::join(other_subscription, this_subscription)
 3559    }
 3560
 3561    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3562        if self.buffer().read(cx).is_singleton() {
 3563            return;
 3564        }
 3565        let snapshot = self.buffer.read(cx).snapshot(cx);
 3566        let buffer_ids: HashSet<BufferId> = self
 3567            .selections
 3568            .disjoint_anchor_ranges()
 3569            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3570            .collect();
 3571        for buffer_id in buffer_ids {
 3572            self.unfold_buffer(buffer_id, cx);
 3573        }
 3574    }
 3575
 3576    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3577    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3578    /// effects of selection change occur at the end of the transaction.
 3579    pub fn change_selections<R>(
 3580        &mut self,
 3581        effects: SelectionEffects,
 3582        window: &mut Window,
 3583        cx: &mut Context<Self>,
 3584        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3585    ) -> R {
 3586        let snapshot = self.display_snapshot(cx);
 3587        if let Some(state) = &mut self.deferred_selection_effects_state {
 3588            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3589            state.effects.completions = effects.completions;
 3590            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3591            let (changed, result) = self.selections.change_with(&snapshot, change);
 3592            state.changed |= changed;
 3593            return result;
 3594        }
 3595        let mut state = DeferredSelectionEffectsState {
 3596            changed: false,
 3597            effects,
 3598            old_cursor_position: self.selections.newest_anchor().head(),
 3599            history_entry: SelectionHistoryEntry {
 3600                selections: self.selections.disjoint_anchors_arc(),
 3601                select_next_state: self.select_next_state.clone(),
 3602                select_prev_state: self.select_prev_state.clone(),
 3603                add_selections_state: self.add_selections_state.clone(),
 3604            },
 3605        };
 3606        let (changed, result) = self.selections.change_with(&snapshot, change);
 3607        state.changed = state.changed || changed;
 3608        if self.defer_selection_effects {
 3609            self.deferred_selection_effects_state = Some(state);
 3610        } else {
 3611            self.apply_selection_effects(state, window, cx);
 3612        }
 3613        result
 3614    }
 3615
 3616    /// Defers the effects of selection change, so that the effects of multiple calls to
 3617    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3618    /// to selection history and the state of popovers based on selection position aren't
 3619    /// erroneously updated.
 3620    pub fn with_selection_effects_deferred<R>(
 3621        &mut self,
 3622        window: &mut Window,
 3623        cx: &mut Context<Self>,
 3624        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3625    ) -> R {
 3626        let already_deferred = self.defer_selection_effects;
 3627        self.defer_selection_effects = true;
 3628        let result = update(self, window, cx);
 3629        if !already_deferred {
 3630            self.defer_selection_effects = false;
 3631            if let Some(state) = self.deferred_selection_effects_state.take() {
 3632                self.apply_selection_effects(state, window, cx);
 3633            }
 3634        }
 3635        result
 3636    }
 3637
 3638    fn apply_selection_effects(
 3639        &mut self,
 3640        state: DeferredSelectionEffectsState,
 3641        window: &mut Window,
 3642        cx: &mut Context<Self>,
 3643    ) {
 3644        if state.changed {
 3645            self.selection_history.push(state.history_entry);
 3646
 3647            if let Some(autoscroll) = state.effects.scroll {
 3648                self.request_autoscroll(autoscroll, cx);
 3649            }
 3650
 3651            let old_cursor_position = &state.old_cursor_position;
 3652
 3653            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3654
 3655            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3656                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3657            }
 3658        }
 3659    }
 3660
 3661    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3662    where
 3663        I: IntoIterator<Item = (Range<S>, T)>,
 3664        S: ToOffset,
 3665        T: Into<Arc<str>>,
 3666    {
 3667        if self.read_only(cx) {
 3668            return;
 3669        }
 3670
 3671        self.buffer
 3672            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3673    }
 3674
 3675    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3676    where
 3677        I: IntoIterator<Item = (Range<S>, T)>,
 3678        S: ToOffset,
 3679        T: Into<Arc<str>>,
 3680    {
 3681        if self.read_only(cx) {
 3682            return;
 3683        }
 3684
 3685        self.buffer.update(cx, |buffer, cx| {
 3686            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3687        });
 3688    }
 3689
 3690    pub fn edit_with_block_indent<I, S, T>(
 3691        &mut self,
 3692        edits: I,
 3693        original_indent_columns: Vec<Option<u32>>,
 3694        cx: &mut Context<Self>,
 3695    ) where
 3696        I: IntoIterator<Item = (Range<S>, T)>,
 3697        S: ToOffset,
 3698        T: Into<Arc<str>>,
 3699    {
 3700        if self.read_only(cx) {
 3701            return;
 3702        }
 3703
 3704        self.buffer.update(cx, |buffer, cx| {
 3705            buffer.edit(
 3706                edits,
 3707                Some(AutoindentMode::Block {
 3708                    original_indent_columns,
 3709                }),
 3710                cx,
 3711            )
 3712        });
 3713    }
 3714
 3715    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3716        self.hide_context_menu(window, cx);
 3717
 3718        match phase {
 3719            SelectPhase::Begin {
 3720                position,
 3721                add,
 3722                click_count,
 3723            } => self.begin_selection(position, add, click_count, window, cx),
 3724            SelectPhase::BeginColumnar {
 3725                position,
 3726                goal_column,
 3727                reset,
 3728                mode,
 3729            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3730            SelectPhase::Extend {
 3731                position,
 3732                click_count,
 3733            } => self.extend_selection(position, click_count, window, cx),
 3734            SelectPhase::Update {
 3735                position,
 3736                goal_column,
 3737                scroll_delta,
 3738            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3739            SelectPhase::End => self.end_selection(window, cx),
 3740        }
 3741    }
 3742
 3743    fn extend_selection(
 3744        &mut self,
 3745        position: DisplayPoint,
 3746        click_count: usize,
 3747        window: &mut Window,
 3748        cx: &mut Context<Self>,
 3749    ) {
 3750        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3751        let tail = self
 3752            .selections
 3753            .newest::<MultiBufferOffset>(&display_map)
 3754            .tail();
 3755        let click_count = click_count.max(match self.selections.select_mode() {
 3756            SelectMode::Character => 1,
 3757            SelectMode::Word(_) => 2,
 3758            SelectMode::Line(_) => 3,
 3759            SelectMode::All => 4,
 3760        });
 3761        self.begin_selection(position, false, click_count, window, cx);
 3762
 3763        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3764
 3765        let current_selection = match self.selections.select_mode() {
 3766            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3767            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3768        };
 3769
 3770        let mut pending_selection = self
 3771            .selections
 3772            .pending_anchor()
 3773            .cloned()
 3774            .expect("extend_selection not called with pending selection");
 3775
 3776        if pending_selection
 3777            .start
 3778            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3779            == Ordering::Greater
 3780        {
 3781            pending_selection.start = current_selection.start;
 3782        }
 3783        if pending_selection
 3784            .end
 3785            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3786            == Ordering::Less
 3787        {
 3788            pending_selection.end = current_selection.end;
 3789            pending_selection.reversed = true;
 3790        }
 3791
 3792        let mut pending_mode = self.selections.pending_mode().unwrap();
 3793        match &mut pending_mode {
 3794            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3795            _ => {}
 3796        }
 3797
 3798        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3799            SelectionEffects::scroll(Autoscroll::fit())
 3800        } else {
 3801            SelectionEffects::no_scroll()
 3802        };
 3803
 3804        self.change_selections(effects, window, cx, |s| {
 3805            s.set_pending(pending_selection.clone(), pending_mode);
 3806            s.set_is_extending(true);
 3807        });
 3808    }
 3809
 3810    fn begin_selection(
 3811        &mut self,
 3812        position: DisplayPoint,
 3813        add: bool,
 3814        click_count: usize,
 3815        window: &mut Window,
 3816        cx: &mut Context<Self>,
 3817    ) {
 3818        if !self.focus_handle.is_focused(window) {
 3819            self.last_focused_descendant = None;
 3820            window.focus(&self.focus_handle, cx);
 3821        }
 3822
 3823        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3824        let buffer = display_map.buffer_snapshot();
 3825        let position = display_map.clip_point(position, Bias::Left);
 3826
 3827        let start;
 3828        let end;
 3829        let mode;
 3830        let mut auto_scroll;
 3831        match click_count {
 3832            1 => {
 3833                start = buffer.anchor_before(position.to_point(&display_map));
 3834                end = start;
 3835                mode = SelectMode::Character;
 3836                auto_scroll = true;
 3837            }
 3838            2 => {
 3839                let position = display_map
 3840                    .clip_point(position, Bias::Left)
 3841                    .to_offset(&display_map, Bias::Left);
 3842                let (range, _) = buffer.surrounding_word(position, None);
 3843                start = buffer.anchor_before(range.start);
 3844                end = buffer.anchor_before(range.end);
 3845                mode = SelectMode::Word(start..end);
 3846                auto_scroll = true;
 3847            }
 3848            3 => {
 3849                let position = display_map
 3850                    .clip_point(position, Bias::Left)
 3851                    .to_point(&display_map);
 3852                let line_start = display_map.prev_line_boundary(position).0;
 3853                let next_line_start = buffer.clip_point(
 3854                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3855                    Bias::Left,
 3856                );
 3857                start = buffer.anchor_before(line_start);
 3858                end = buffer.anchor_before(next_line_start);
 3859                mode = SelectMode::Line(start..end);
 3860                auto_scroll = true;
 3861            }
 3862            _ => {
 3863                start = buffer.anchor_before(MultiBufferOffset(0));
 3864                end = buffer.anchor_before(buffer.len());
 3865                mode = SelectMode::All;
 3866                auto_scroll = false;
 3867            }
 3868        }
 3869        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3870
 3871        let point_to_delete: Option<usize> = {
 3872            let selected_points: Vec<Selection<Point>> =
 3873                self.selections.disjoint_in_range(start..end, &display_map);
 3874
 3875            if !add || click_count > 1 {
 3876                None
 3877            } else if !selected_points.is_empty() {
 3878                Some(selected_points[0].id)
 3879            } else {
 3880                let clicked_point_already_selected =
 3881                    self.selections.disjoint_anchors().iter().find(|selection| {
 3882                        selection.start.to_point(buffer) == start.to_point(buffer)
 3883                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3884                    });
 3885
 3886                clicked_point_already_selected.map(|selection| selection.id)
 3887            }
 3888        };
 3889
 3890        let selections_count = self.selections.count();
 3891        let effects = if auto_scroll {
 3892            SelectionEffects::default()
 3893        } else {
 3894            SelectionEffects::no_scroll()
 3895        };
 3896
 3897        self.change_selections(effects, window, cx, |s| {
 3898            if let Some(point_to_delete) = point_to_delete {
 3899                s.delete(point_to_delete);
 3900
 3901                if selections_count == 1 {
 3902                    s.set_pending_anchor_range(start..end, mode);
 3903                }
 3904            } else {
 3905                if !add {
 3906                    s.clear_disjoint();
 3907                }
 3908
 3909                s.set_pending_anchor_range(start..end, mode);
 3910            }
 3911        });
 3912    }
 3913
 3914    fn begin_columnar_selection(
 3915        &mut self,
 3916        position: DisplayPoint,
 3917        goal_column: u32,
 3918        reset: bool,
 3919        mode: ColumnarMode,
 3920        window: &mut Window,
 3921        cx: &mut Context<Self>,
 3922    ) {
 3923        if !self.focus_handle.is_focused(window) {
 3924            self.last_focused_descendant = None;
 3925            window.focus(&self.focus_handle, cx);
 3926        }
 3927
 3928        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3929
 3930        if reset {
 3931            let pointer_position = display_map
 3932                .buffer_snapshot()
 3933                .anchor_before(position.to_point(&display_map));
 3934
 3935            self.change_selections(
 3936                SelectionEffects::scroll(Autoscroll::newest()),
 3937                window,
 3938                cx,
 3939                |s| {
 3940                    s.clear_disjoint();
 3941                    s.set_pending_anchor_range(
 3942                        pointer_position..pointer_position,
 3943                        SelectMode::Character,
 3944                    );
 3945                },
 3946            );
 3947        };
 3948
 3949        let tail = self.selections.newest::<Point>(&display_map).tail();
 3950        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3951        self.columnar_selection_state = match mode {
 3952            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3953                selection_tail: selection_anchor,
 3954                display_point: if reset {
 3955                    if position.column() != goal_column {
 3956                        Some(DisplayPoint::new(position.row(), goal_column))
 3957                    } else {
 3958                        None
 3959                    }
 3960                } else {
 3961                    None
 3962                },
 3963            }),
 3964            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3965                selection_tail: selection_anchor,
 3966            }),
 3967        };
 3968
 3969        if !reset {
 3970            self.select_columns(position, goal_column, &display_map, window, cx);
 3971        }
 3972    }
 3973
 3974    fn update_selection(
 3975        &mut self,
 3976        position: DisplayPoint,
 3977        goal_column: u32,
 3978        scroll_delta: gpui::Point<f32>,
 3979        window: &mut Window,
 3980        cx: &mut Context<Self>,
 3981    ) {
 3982        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3983
 3984        if self.columnar_selection_state.is_some() {
 3985            self.select_columns(position, goal_column, &display_map, window, cx);
 3986        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3987            let buffer = display_map.buffer_snapshot();
 3988            let head;
 3989            let tail;
 3990            let mode = self.selections.pending_mode().unwrap();
 3991            match &mode {
 3992                SelectMode::Character => {
 3993                    head = position.to_point(&display_map);
 3994                    tail = pending.tail().to_point(buffer);
 3995                }
 3996                SelectMode::Word(original_range) => {
 3997                    let offset = display_map
 3998                        .clip_point(position, Bias::Left)
 3999                        .to_offset(&display_map, Bias::Left);
 4000                    let original_range = original_range.to_offset(buffer);
 4001
 4002                    let head_offset = if buffer.is_inside_word(offset, None)
 4003                        || original_range.contains(&offset)
 4004                    {
 4005                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4006                        if word_range.start < original_range.start {
 4007                            word_range.start
 4008                        } else {
 4009                            word_range.end
 4010                        }
 4011                    } else {
 4012                        offset
 4013                    };
 4014
 4015                    head = head_offset.to_point(buffer);
 4016                    if head_offset <= original_range.start {
 4017                        tail = original_range.end.to_point(buffer);
 4018                    } else {
 4019                        tail = original_range.start.to_point(buffer);
 4020                    }
 4021                }
 4022                SelectMode::Line(original_range) => {
 4023                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4024
 4025                    let position = display_map
 4026                        .clip_point(position, Bias::Left)
 4027                        .to_point(&display_map);
 4028                    let line_start = display_map.prev_line_boundary(position).0;
 4029                    let next_line_start = buffer.clip_point(
 4030                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4031                        Bias::Left,
 4032                    );
 4033
 4034                    if line_start < original_range.start {
 4035                        head = line_start
 4036                    } else {
 4037                        head = next_line_start
 4038                    }
 4039
 4040                    if head <= original_range.start {
 4041                        tail = original_range.end;
 4042                    } else {
 4043                        tail = original_range.start;
 4044                    }
 4045                }
 4046                SelectMode::All => {
 4047                    return;
 4048                }
 4049            };
 4050
 4051            if head < tail {
 4052                pending.start = buffer.anchor_before(head);
 4053                pending.end = buffer.anchor_before(tail);
 4054                pending.reversed = true;
 4055            } else {
 4056                pending.start = buffer.anchor_before(tail);
 4057                pending.end = buffer.anchor_before(head);
 4058                pending.reversed = false;
 4059            }
 4060
 4061            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4062                s.set_pending(pending.clone(), mode);
 4063            });
 4064        } else {
 4065            log::error!("update_selection dispatched with no pending selection");
 4066            return;
 4067        }
 4068
 4069        self.apply_scroll_delta(scroll_delta, window, cx);
 4070        cx.notify();
 4071    }
 4072
 4073    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4074        self.columnar_selection_state.take();
 4075        if let Some(pending_mode) = self.selections.pending_mode() {
 4076            let selections = self
 4077                .selections
 4078                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4079            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4080                s.select(selections);
 4081                s.clear_pending();
 4082                if s.is_extending() {
 4083                    s.set_is_extending(false);
 4084                } else {
 4085                    s.set_select_mode(pending_mode);
 4086                }
 4087            });
 4088        }
 4089    }
 4090
 4091    fn select_columns(
 4092        &mut self,
 4093        head: DisplayPoint,
 4094        goal_column: u32,
 4095        display_map: &DisplaySnapshot,
 4096        window: &mut Window,
 4097        cx: &mut Context<Self>,
 4098    ) {
 4099        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4100            return;
 4101        };
 4102
 4103        let tail = match columnar_state {
 4104            ColumnarSelectionState::FromMouse {
 4105                selection_tail,
 4106                display_point,
 4107            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4108            ColumnarSelectionState::FromSelection { selection_tail } => {
 4109                selection_tail.to_display_point(display_map)
 4110            }
 4111        };
 4112
 4113        let start_row = cmp::min(tail.row(), head.row());
 4114        let end_row = cmp::max(tail.row(), head.row());
 4115        let start_column = cmp::min(tail.column(), goal_column);
 4116        let end_column = cmp::max(tail.column(), goal_column);
 4117        let reversed = start_column < tail.column();
 4118
 4119        let selection_ranges = (start_row.0..=end_row.0)
 4120            .map(DisplayRow)
 4121            .filter_map(|row| {
 4122                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4123                    || start_column <= display_map.line_len(row))
 4124                    && !display_map.is_block_line(row)
 4125                {
 4126                    let start = display_map
 4127                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4128                        .to_point(display_map);
 4129                    let end = display_map
 4130                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4131                        .to_point(display_map);
 4132                    if reversed {
 4133                        Some(end..start)
 4134                    } else {
 4135                        Some(start..end)
 4136                    }
 4137                } else {
 4138                    None
 4139                }
 4140            })
 4141            .collect::<Vec<_>>();
 4142        if selection_ranges.is_empty() {
 4143            return;
 4144        }
 4145
 4146        let ranges = match columnar_state {
 4147            ColumnarSelectionState::FromMouse { .. } => {
 4148                let mut non_empty_ranges = selection_ranges
 4149                    .iter()
 4150                    .filter(|selection_range| selection_range.start != selection_range.end)
 4151                    .peekable();
 4152                if non_empty_ranges.peek().is_some() {
 4153                    non_empty_ranges.cloned().collect()
 4154                } else {
 4155                    selection_ranges
 4156                }
 4157            }
 4158            _ => selection_ranges,
 4159        };
 4160
 4161        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4162            s.select_ranges(ranges);
 4163        });
 4164        cx.notify();
 4165    }
 4166
 4167    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4168        self.selections
 4169            .all_adjusted(snapshot)
 4170            .iter()
 4171            .any(|selection| !selection.is_empty())
 4172    }
 4173
 4174    pub fn has_pending_nonempty_selection(&self) -> bool {
 4175        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4176            Some(Selection { start, end, .. }) => start != end,
 4177            None => false,
 4178        };
 4179
 4180        pending_nonempty_selection
 4181            || (self.columnar_selection_state.is_some()
 4182                && self.selections.disjoint_anchors().len() > 1)
 4183    }
 4184
 4185    pub fn has_pending_selection(&self) -> bool {
 4186        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4187    }
 4188
 4189    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4190        self.selection_mark_mode = false;
 4191        self.selection_drag_state = SelectionDragState::None;
 4192
 4193        if self.dismiss_menus_and_popups(true, window, cx) {
 4194            cx.notify();
 4195            return;
 4196        }
 4197        if self.clear_expanded_diff_hunks(cx) {
 4198            cx.notify();
 4199            return;
 4200        }
 4201        if self.show_git_blame_gutter {
 4202            self.show_git_blame_gutter = false;
 4203            cx.notify();
 4204            return;
 4205        }
 4206
 4207        if self.mode.is_full()
 4208            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4209        {
 4210            cx.notify();
 4211            return;
 4212        }
 4213
 4214        cx.propagate();
 4215    }
 4216
 4217    pub fn dismiss_menus_and_popups(
 4218        &mut self,
 4219        is_user_requested: bool,
 4220        window: &mut Window,
 4221        cx: &mut Context<Self>,
 4222    ) -> bool {
 4223        let mut dismissed = false;
 4224
 4225        dismissed |= self.take_rename(false, window, cx).is_some();
 4226        dismissed |= self.hide_blame_popover(true, cx);
 4227        dismissed |= hide_hover(self, cx);
 4228        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4229        dismissed |= self.hide_context_menu(window, cx).is_some();
 4230        dismissed |= self.mouse_context_menu.take().is_some();
 4231        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4232        dismissed |= self.snippet_stack.pop().is_some();
 4233
 4234        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4235            self.dismiss_diagnostics(cx);
 4236            dismissed = true;
 4237        }
 4238
 4239        dismissed
 4240    }
 4241
 4242    fn linked_editing_ranges_for(
 4243        &self,
 4244        selection: Range<text::Anchor>,
 4245        cx: &App,
 4246    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4247        if self.linked_edit_ranges.is_empty() {
 4248            return None;
 4249        }
 4250        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4251            selection.end.buffer_id.and_then(|end_buffer_id| {
 4252                if selection.start.buffer_id != Some(end_buffer_id) {
 4253                    return None;
 4254                }
 4255                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4256                let snapshot = buffer.read(cx).snapshot();
 4257                self.linked_edit_ranges
 4258                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4259                    .map(|ranges| (ranges, snapshot, buffer))
 4260            })?;
 4261        use text::ToOffset as TO;
 4262        // find offset from the start of current range to current cursor position
 4263        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4264
 4265        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4266        let start_difference = start_offset - start_byte_offset;
 4267        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4268        let end_difference = end_offset - start_byte_offset;
 4269        // Current range has associated linked ranges.
 4270        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4271        for range in linked_ranges.iter() {
 4272            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4273            let end_offset = start_offset + end_difference;
 4274            let start_offset = start_offset + start_difference;
 4275            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4276                continue;
 4277            }
 4278            if self.selections.disjoint_anchor_ranges().any(|s| {
 4279                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4280                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4281                {
 4282                    return false;
 4283                }
 4284                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4285                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4286            }) {
 4287                continue;
 4288            }
 4289            let start = buffer_snapshot.anchor_after(start_offset);
 4290            let end = buffer_snapshot.anchor_after(end_offset);
 4291            linked_edits
 4292                .entry(buffer.clone())
 4293                .or_default()
 4294                .push(start..end);
 4295        }
 4296        Some(linked_edits)
 4297    }
 4298
 4299    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4300        let text: Arc<str> = text.into();
 4301
 4302        if self.read_only(cx) {
 4303            return;
 4304        }
 4305
 4306        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4307
 4308        self.unfold_buffers_with_selections(cx);
 4309
 4310        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4311        let mut bracket_inserted = false;
 4312        let mut edits = Vec::new();
 4313        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4314        let mut new_selections = Vec::with_capacity(selections.len());
 4315        let mut new_autoclose_regions = Vec::new();
 4316        let snapshot = self.buffer.read(cx).read(cx);
 4317        let mut clear_linked_edit_ranges = false;
 4318        let mut all_selections_read_only = true;
 4319
 4320        for (selection, autoclose_region) in
 4321            self.selections_with_autoclose_regions(selections, &snapshot)
 4322        {
 4323            if snapshot
 4324                .point_to_buffer_point(selection.head())
 4325                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4326            {
 4327                continue;
 4328            }
 4329            if snapshot
 4330                .point_to_buffer_point(selection.tail())
 4331                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4332            {
 4333                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4334                continue;
 4335            }
 4336            all_selections_read_only = false;
 4337
 4338            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4339                // Determine if the inserted text matches the opening or closing
 4340                // bracket of any of this language's bracket pairs.
 4341                let mut bracket_pair = None;
 4342                let mut is_bracket_pair_start = false;
 4343                let mut is_bracket_pair_end = false;
 4344                if !text.is_empty() {
 4345                    let mut bracket_pair_matching_end = None;
 4346                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4347                    //  and they are removing the character that triggered IME popup.
 4348                    for (pair, enabled) in scope.brackets() {
 4349                        if !pair.close && !pair.surround {
 4350                            continue;
 4351                        }
 4352
 4353                        if enabled && pair.start.ends_with(text.as_ref()) {
 4354                            let prefix_len = pair.start.len() - text.len();
 4355                            let preceding_text_matches_prefix = prefix_len == 0
 4356                                || (selection.start.column >= (prefix_len as u32)
 4357                                    && snapshot.contains_str_at(
 4358                                        Point::new(
 4359                                            selection.start.row,
 4360                                            selection.start.column - (prefix_len as u32),
 4361                                        ),
 4362                                        &pair.start[..prefix_len],
 4363                                    ));
 4364                            if preceding_text_matches_prefix {
 4365                                bracket_pair = Some(pair.clone());
 4366                                is_bracket_pair_start = true;
 4367                                break;
 4368                            }
 4369                        }
 4370                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4371                        {
 4372                            // take first bracket pair matching end, but don't break in case a later bracket
 4373                            // pair matches start
 4374                            bracket_pair_matching_end = Some(pair.clone());
 4375                        }
 4376                    }
 4377                    if let Some(end) = bracket_pair_matching_end
 4378                        && bracket_pair.is_none()
 4379                    {
 4380                        bracket_pair = Some(end);
 4381                        is_bracket_pair_end = true;
 4382                    }
 4383                }
 4384
 4385                if let Some(bracket_pair) = bracket_pair {
 4386                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4387                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4388                    let auto_surround =
 4389                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4390                    if selection.is_empty() {
 4391                        if is_bracket_pair_start {
 4392                            // If the inserted text is a suffix of an opening bracket and the
 4393                            // selection is preceded by the rest of the opening bracket, then
 4394                            // insert the closing bracket.
 4395                            let following_text_allows_autoclose = snapshot
 4396                                .chars_at(selection.start)
 4397                                .next()
 4398                                .is_none_or(|c| scope.should_autoclose_before(c));
 4399
 4400                            let preceding_text_allows_autoclose = selection.start.column == 0
 4401                                || snapshot
 4402                                    .reversed_chars_at(selection.start)
 4403                                    .next()
 4404                                    .is_none_or(|c| {
 4405                                        bracket_pair.start != bracket_pair.end
 4406                                            || !snapshot
 4407                                                .char_classifier_at(selection.start)
 4408                                                .is_word(c)
 4409                                    });
 4410
 4411                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4412                                && bracket_pair.start.len() == 1
 4413                            {
 4414                                let target = bracket_pair.start.chars().next().unwrap();
 4415                                let mut byte_offset = 0u32;
 4416                                let current_line_count = snapshot
 4417                                    .reversed_chars_at(selection.start)
 4418                                    .take_while(|&c| c != '\n')
 4419                                    .filter(|c| {
 4420                                        byte_offset += c.len_utf8() as u32;
 4421                                        if *c != target {
 4422                                            return false;
 4423                                        }
 4424
 4425                                        let point = Point::new(
 4426                                            selection.start.row,
 4427                                            selection.start.column.saturating_sub(byte_offset),
 4428                                        );
 4429
 4430                                        let is_enabled = snapshot
 4431                                            .language_scope_at(point)
 4432                                            .and_then(|scope| {
 4433                                                scope
 4434                                                    .brackets()
 4435                                                    .find(|(pair, _)| {
 4436                                                        pair.start == bracket_pair.start
 4437                                                    })
 4438                                                    .map(|(_, enabled)| enabled)
 4439                                            })
 4440                                            .unwrap_or(true);
 4441
 4442                                        let is_delimiter = snapshot
 4443                                            .language_scope_at(Point::new(
 4444                                                point.row,
 4445                                                point.column + 1,
 4446                                            ))
 4447                                            .and_then(|scope| {
 4448                                                scope
 4449                                                    .brackets()
 4450                                                    .find(|(pair, _)| {
 4451                                                        pair.start == bracket_pair.start
 4452                                                    })
 4453                                                    .map(|(_, enabled)| !enabled)
 4454                                            })
 4455                                            .unwrap_or(false);
 4456
 4457                                        is_enabled && !is_delimiter
 4458                                    })
 4459                                    .count();
 4460                                current_line_count % 2 == 1
 4461                            } else {
 4462                                false
 4463                            };
 4464
 4465                            if autoclose
 4466                                && bracket_pair.close
 4467                                && following_text_allows_autoclose
 4468                                && preceding_text_allows_autoclose
 4469                                && !is_closing_quote
 4470                            {
 4471                                let anchor = snapshot.anchor_before(selection.end);
 4472                                new_selections.push((selection.map(|_| anchor), text.len()));
 4473                                new_autoclose_regions.push((
 4474                                    anchor,
 4475                                    text.len(),
 4476                                    selection.id,
 4477                                    bracket_pair.clone(),
 4478                                ));
 4479                                edits.push((
 4480                                    selection.range(),
 4481                                    format!("{}{}", text, bracket_pair.end).into(),
 4482                                ));
 4483                                bracket_inserted = true;
 4484                                continue;
 4485                            }
 4486                        }
 4487
 4488                        if let Some(region) = autoclose_region {
 4489                            // If the selection is followed by an auto-inserted closing bracket,
 4490                            // then don't insert that closing bracket again; just move the selection
 4491                            // past the closing bracket.
 4492                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4493                                && text.as_ref() == region.pair.end.as_str()
 4494                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4495                            if should_skip {
 4496                                let anchor = snapshot.anchor_after(selection.end);
 4497                                new_selections
 4498                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4499                                continue;
 4500                            }
 4501                        }
 4502
 4503                        let always_treat_brackets_as_autoclosed = snapshot
 4504                            .language_settings_at(selection.start, cx)
 4505                            .always_treat_brackets_as_autoclosed;
 4506                        if always_treat_brackets_as_autoclosed
 4507                            && is_bracket_pair_end
 4508                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4509                        {
 4510                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4511                            // and the inserted text is a closing bracket and the selection is followed
 4512                            // by the closing bracket then move the selection past the closing bracket.
 4513                            let anchor = snapshot.anchor_after(selection.end);
 4514                            new_selections.push((selection.map(|_| anchor), text.len()));
 4515                            continue;
 4516                        }
 4517                    }
 4518                    // If an opening bracket is 1 character long and is typed while
 4519                    // text is selected, then surround that text with the bracket pair.
 4520                    else if auto_surround
 4521                        && bracket_pair.surround
 4522                        && is_bracket_pair_start
 4523                        && bracket_pair.start.chars().count() == 1
 4524                    {
 4525                        edits.push((selection.start..selection.start, text.clone()));
 4526                        edits.push((
 4527                            selection.end..selection.end,
 4528                            bracket_pair.end.as_str().into(),
 4529                        ));
 4530                        bracket_inserted = true;
 4531                        new_selections.push((
 4532                            Selection {
 4533                                id: selection.id,
 4534                                start: snapshot.anchor_after(selection.start),
 4535                                end: snapshot.anchor_before(selection.end),
 4536                                reversed: selection.reversed,
 4537                                goal: selection.goal,
 4538                            },
 4539                            0,
 4540                        ));
 4541                        continue;
 4542                    }
 4543                }
 4544            }
 4545
 4546            if self.auto_replace_emoji_shortcode
 4547                && selection.is_empty()
 4548                && text.as_ref().ends_with(':')
 4549                && let Some(possible_emoji_short_code) =
 4550                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4551                && !possible_emoji_short_code.is_empty()
 4552                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4553            {
 4554                let emoji_shortcode_start = Point::new(
 4555                    selection.start.row,
 4556                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4557                );
 4558
 4559                // Remove shortcode from buffer
 4560                edits.push((
 4561                    emoji_shortcode_start..selection.start,
 4562                    "".to_string().into(),
 4563                ));
 4564                new_selections.push((
 4565                    Selection {
 4566                        id: selection.id,
 4567                        start: snapshot.anchor_after(emoji_shortcode_start),
 4568                        end: snapshot.anchor_before(selection.start),
 4569                        reversed: selection.reversed,
 4570                        goal: selection.goal,
 4571                    },
 4572                    0,
 4573                ));
 4574
 4575                // Insert emoji
 4576                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4577                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4578                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4579
 4580                continue;
 4581            }
 4582
 4583            // If not handling any auto-close operation, then just replace the selected
 4584            // text with the given input and move the selection to the end of the
 4585            // newly inserted text.
 4586            let anchor = snapshot.anchor_after(selection.end);
 4587            if !self.linked_edit_ranges.is_empty() {
 4588                let start_anchor = snapshot.anchor_before(selection.start);
 4589
 4590                let is_word_char = text.chars().next().is_none_or(|char| {
 4591                    let classifier = snapshot
 4592                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4593                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4594                    classifier.is_word(char)
 4595                });
 4596
 4597                if is_word_char {
 4598                    if let Some(ranges) = self
 4599                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4600                    {
 4601                        for (buffer, edits) in ranges {
 4602                            linked_edits
 4603                                .entry(buffer.clone())
 4604                                .or_default()
 4605                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4606                        }
 4607                    }
 4608                } else {
 4609                    clear_linked_edit_ranges = true;
 4610                }
 4611            }
 4612
 4613            new_selections.push((selection.map(|_| anchor), 0));
 4614            edits.push((selection.start..selection.end, text.clone()));
 4615        }
 4616
 4617        if all_selections_read_only {
 4618            return;
 4619        }
 4620
 4621        drop(snapshot);
 4622
 4623        self.transact(window, cx, |this, window, cx| {
 4624            if clear_linked_edit_ranges {
 4625                this.linked_edit_ranges.clear();
 4626            }
 4627            let initial_buffer_versions =
 4628                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4629
 4630            this.buffer.update(cx, |buffer, cx| {
 4631                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4632            });
 4633            for (buffer, edits) in linked_edits {
 4634                buffer.update(cx, |buffer, cx| {
 4635                    let snapshot = buffer.snapshot();
 4636                    let edits = edits
 4637                        .into_iter()
 4638                        .map(|(range, text)| {
 4639                            use text::ToPoint as TP;
 4640                            let end_point = TP::to_point(&range.end, &snapshot);
 4641                            let start_point = TP::to_point(&range.start, &snapshot);
 4642                            (start_point..end_point, text)
 4643                        })
 4644                        .sorted_by_key(|(range, _)| range.start);
 4645                    buffer.edit(edits, None, cx);
 4646                })
 4647            }
 4648            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4649            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4650            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4651            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4652                new_anchor_selections,
 4653                &map,
 4654            )
 4655            .zip(new_selection_deltas)
 4656            .map(|(selection, delta)| Selection {
 4657                id: selection.id,
 4658                start: selection.start + delta,
 4659                end: selection.end + delta,
 4660                reversed: selection.reversed,
 4661                goal: SelectionGoal::None,
 4662            })
 4663            .collect::<Vec<_>>();
 4664
 4665            let mut i = 0;
 4666            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4667                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4668                let start = map.buffer_snapshot().anchor_before(position);
 4669                let end = map.buffer_snapshot().anchor_after(position);
 4670                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4671                    match existing_state
 4672                        .range
 4673                        .start
 4674                        .cmp(&start, map.buffer_snapshot())
 4675                    {
 4676                        Ordering::Less => i += 1,
 4677                        Ordering::Greater => break,
 4678                        Ordering::Equal => {
 4679                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4680                                Ordering::Less => i += 1,
 4681                                Ordering::Equal => break,
 4682                                Ordering::Greater => break,
 4683                            }
 4684                        }
 4685                    }
 4686                }
 4687                this.autoclose_regions.insert(
 4688                    i,
 4689                    AutocloseRegion {
 4690                        selection_id,
 4691                        range: start..end,
 4692                        pair,
 4693                    },
 4694                );
 4695            }
 4696
 4697            let had_active_edit_prediction = this.has_active_edit_prediction();
 4698            this.change_selections(
 4699                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4700                window,
 4701                cx,
 4702                |s| s.select(new_selections),
 4703            );
 4704
 4705            if !bracket_inserted
 4706                && let Some(on_type_format_task) =
 4707                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4708            {
 4709                on_type_format_task.detach_and_log_err(cx);
 4710            }
 4711
 4712            let editor_settings = EditorSettings::get_global(cx);
 4713            if bracket_inserted
 4714                && (editor_settings.auto_signature_help
 4715                    || editor_settings.show_signature_help_after_edits)
 4716            {
 4717                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4718            }
 4719
 4720            let trigger_in_words =
 4721                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4722            if this.hard_wrap.is_some() {
 4723                let latest: Range<Point> = this.selections.newest(&map).range();
 4724                if latest.is_empty()
 4725                    && this
 4726                        .buffer()
 4727                        .read(cx)
 4728                        .snapshot(cx)
 4729                        .line_len(MultiBufferRow(latest.start.row))
 4730                        == latest.start.column
 4731                {
 4732                    this.rewrap_impl(
 4733                        RewrapOptions {
 4734                            override_language_settings: true,
 4735                            preserve_existing_whitespace: true,
 4736                        },
 4737                        cx,
 4738                    )
 4739                }
 4740            }
 4741            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4742            refresh_linked_ranges(this, window, cx);
 4743            this.refresh_edit_prediction(true, false, window, cx);
 4744            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4745        });
 4746    }
 4747
 4748    fn find_possible_emoji_shortcode_at_position(
 4749        snapshot: &MultiBufferSnapshot,
 4750        position: Point,
 4751    ) -> Option<String> {
 4752        let mut chars = Vec::new();
 4753        let mut found_colon = false;
 4754        for char in snapshot.reversed_chars_at(position).take(100) {
 4755            // Found a possible emoji shortcode in the middle of the buffer
 4756            if found_colon {
 4757                if char.is_whitespace() {
 4758                    chars.reverse();
 4759                    return Some(chars.iter().collect());
 4760                }
 4761                // If the previous character is not a whitespace, we are in the middle of a word
 4762                // and we only want to complete the shortcode if the word is made up of other emojis
 4763                let mut containing_word = String::new();
 4764                for ch in snapshot
 4765                    .reversed_chars_at(position)
 4766                    .skip(chars.len() + 1)
 4767                    .take(100)
 4768                {
 4769                    if ch.is_whitespace() {
 4770                        break;
 4771                    }
 4772                    containing_word.push(ch);
 4773                }
 4774                let containing_word = containing_word.chars().rev().collect::<String>();
 4775                if util::word_consists_of_emojis(containing_word.as_str()) {
 4776                    chars.reverse();
 4777                    return Some(chars.iter().collect());
 4778                }
 4779            }
 4780
 4781            if char.is_whitespace() || !char.is_ascii() {
 4782                return None;
 4783            }
 4784            if char == ':' {
 4785                found_colon = true;
 4786            } else {
 4787                chars.push(char);
 4788            }
 4789        }
 4790        // Found a possible emoji shortcode at the beginning of the buffer
 4791        chars.reverse();
 4792        Some(chars.iter().collect())
 4793    }
 4794
 4795    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4796        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4797        self.transact(window, cx, |this, window, cx| {
 4798            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4799                let selections = this
 4800                    .selections
 4801                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4802                let multi_buffer = this.buffer.read(cx);
 4803                let buffer = multi_buffer.snapshot(cx);
 4804                selections
 4805                    .iter()
 4806                    .map(|selection| {
 4807                        let start_point = selection.start.to_point(&buffer);
 4808                        let mut existing_indent =
 4809                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4810                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4811                        let start = selection.start;
 4812                        let end = selection.end;
 4813                        let selection_is_empty = start == end;
 4814                        let language_scope = buffer.language_scope_at(start);
 4815                        let (comment_delimiter, doc_delimiter, newline_formatting) =
 4816                            if let Some(language) = &language_scope {
 4817                                let mut newline_formatting =
 4818                                    NewlineFormatting::new(&buffer, start..end, language);
 4819
 4820                                // Comment extension on newline is allowed only for cursor selections
 4821                                let comment_delimiter = maybe!({
 4822                                    if !selection_is_empty {
 4823                                        return None;
 4824                                    }
 4825
 4826                                    if !multi_buffer.language_settings(cx).extend_comment_on_newline
 4827                                    {
 4828                                        return None;
 4829                                    }
 4830
 4831                                    return comment_delimiter_for_newline(
 4832                                        &start_point,
 4833                                        &buffer,
 4834                                        language,
 4835                                    );
 4836                                });
 4837
 4838                                let doc_delimiter = maybe!({
 4839                                    if !selection_is_empty {
 4840                                        return None;
 4841                                    }
 4842
 4843                                    if !multi_buffer.language_settings(cx).extend_comment_on_newline
 4844                                    {
 4845                                        return None;
 4846                                    }
 4847
 4848                                    return documentation_delimiter_for_newline(
 4849                                        &start_point,
 4850                                        &buffer,
 4851                                        language,
 4852                                        &mut newline_formatting,
 4853                                    );
 4854                                });
 4855
 4856                                (comment_delimiter, doc_delimiter, newline_formatting)
 4857                            } else {
 4858                                (None, None, NewlineFormatting::default())
 4859                            };
 4860
 4861                        let prevent_auto_indent = doc_delimiter.is_some();
 4862                        let delimiter = comment_delimiter.or(doc_delimiter);
 4863
 4864                        let capacity_for_delimiter =
 4865                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4866                        let mut new_text = String::with_capacity(
 4867                            1 + capacity_for_delimiter
 4868                                + existing_indent.len as usize
 4869                                + newline_formatting.indent_on_newline.len as usize
 4870                                + newline_formatting.indent_on_extra_newline.len as usize,
 4871                        );
 4872                        new_text.push('\n');
 4873                        new_text.extend(existing_indent.chars());
 4874                        new_text.extend(newline_formatting.indent_on_newline.chars());
 4875
 4876                        if let Some(delimiter) = &delimiter {
 4877                            new_text.push_str(delimiter);
 4878                        }
 4879
 4880                        if newline_formatting.insert_extra_newline {
 4881                            new_text.push('\n');
 4882                            new_text.extend(existing_indent.chars());
 4883                            new_text.extend(newline_formatting.indent_on_extra_newline.chars());
 4884                        }
 4885
 4886                        let anchor = buffer.anchor_after(end);
 4887                        let new_selection = selection.map(|_| anchor);
 4888                        (
 4889                            ((start..end, new_text), prevent_auto_indent),
 4890                            (newline_formatting.insert_extra_newline, new_selection),
 4891                        )
 4892                    })
 4893                    .unzip()
 4894            };
 4895
 4896            let mut auto_indent_edits = Vec::new();
 4897            let mut edits = Vec::new();
 4898            for (edit, prevent_auto_indent) in edits_with_flags {
 4899                if prevent_auto_indent {
 4900                    edits.push(edit);
 4901                } else {
 4902                    auto_indent_edits.push(edit);
 4903                }
 4904            }
 4905            if !edits.is_empty() {
 4906                this.edit(edits, cx);
 4907            }
 4908            if !auto_indent_edits.is_empty() {
 4909                this.edit_with_autoindent(auto_indent_edits, cx);
 4910            }
 4911
 4912            let buffer = this.buffer.read(cx).snapshot(cx);
 4913            let new_selections = selection_info
 4914                .into_iter()
 4915                .map(|(extra_newline_inserted, new_selection)| {
 4916                    let mut cursor = new_selection.end.to_point(&buffer);
 4917                    if extra_newline_inserted {
 4918                        cursor.row -= 1;
 4919                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4920                    }
 4921                    new_selection.map(|_| cursor)
 4922                })
 4923                .collect();
 4924
 4925            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4926            this.refresh_edit_prediction(true, false, window, cx);
 4927            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 4928                task.detach_and_log_err(cx);
 4929            }
 4930        });
 4931    }
 4932
 4933    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4934        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4935
 4936        let buffer = self.buffer.read(cx);
 4937        let snapshot = buffer.snapshot(cx);
 4938
 4939        let mut edits = Vec::new();
 4940        let mut rows = Vec::new();
 4941
 4942        for (rows_inserted, selection) in self
 4943            .selections
 4944            .all_adjusted(&self.display_snapshot(cx))
 4945            .into_iter()
 4946            .enumerate()
 4947        {
 4948            let cursor = selection.head();
 4949            let row = cursor.row;
 4950
 4951            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4952
 4953            let newline = "\n".to_string();
 4954            edits.push((start_of_line..start_of_line, newline));
 4955
 4956            rows.push(row + rows_inserted as u32);
 4957        }
 4958
 4959        self.transact(window, cx, |editor, window, cx| {
 4960            editor.edit(edits, cx);
 4961
 4962            editor.change_selections(Default::default(), window, cx, |s| {
 4963                let mut index = 0;
 4964                s.move_cursors_with(|map, _, _| {
 4965                    let row = rows[index];
 4966                    index += 1;
 4967
 4968                    let point = Point::new(row, 0);
 4969                    let boundary = map.next_line_boundary(point).1;
 4970                    let clipped = map.clip_point(boundary, Bias::Left);
 4971
 4972                    (clipped, SelectionGoal::None)
 4973                });
 4974            });
 4975
 4976            let mut indent_edits = Vec::new();
 4977            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4978            for row in rows {
 4979                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4980                for (row, indent) in indents {
 4981                    if indent.len == 0 {
 4982                        continue;
 4983                    }
 4984
 4985                    let text = match indent.kind {
 4986                        IndentKind::Space => " ".repeat(indent.len as usize),
 4987                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4988                    };
 4989                    let point = Point::new(row.0, 0);
 4990                    indent_edits.push((point..point, text));
 4991                }
 4992            }
 4993            editor.edit(indent_edits, cx);
 4994            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 4995                format.detach_and_log_err(cx);
 4996            }
 4997        });
 4998    }
 4999
 5000    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5001        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5002
 5003        let buffer = self.buffer.read(cx);
 5004        let snapshot = buffer.snapshot(cx);
 5005
 5006        let mut edits = Vec::new();
 5007        let mut rows = Vec::new();
 5008        let mut rows_inserted = 0;
 5009
 5010        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5011            let cursor = selection.head();
 5012            let row = cursor.row;
 5013
 5014            let point = Point::new(row + 1, 0);
 5015            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5016
 5017            let newline = "\n".to_string();
 5018            edits.push((start_of_line..start_of_line, newline));
 5019
 5020            rows_inserted += 1;
 5021            rows.push(row + rows_inserted);
 5022        }
 5023
 5024        self.transact(window, cx, |editor, window, cx| {
 5025            editor.edit(edits, cx);
 5026
 5027            editor.change_selections(Default::default(), window, cx, |s| {
 5028                let mut index = 0;
 5029                s.move_cursors_with(|map, _, _| {
 5030                    let row = rows[index];
 5031                    index += 1;
 5032
 5033                    let point = Point::new(row, 0);
 5034                    let boundary = map.next_line_boundary(point).1;
 5035                    let clipped = map.clip_point(boundary, Bias::Left);
 5036
 5037                    (clipped, SelectionGoal::None)
 5038                });
 5039            });
 5040
 5041            let mut indent_edits = Vec::new();
 5042            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5043            for row in rows {
 5044                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5045                for (row, indent) in indents {
 5046                    if indent.len == 0 {
 5047                        continue;
 5048                    }
 5049
 5050                    let text = match indent.kind {
 5051                        IndentKind::Space => " ".repeat(indent.len as usize),
 5052                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5053                    };
 5054                    let point = Point::new(row.0, 0);
 5055                    indent_edits.push((point..point, text));
 5056                }
 5057            }
 5058            editor.edit(indent_edits, cx);
 5059            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5060                format.detach_and_log_err(cx);
 5061            }
 5062        });
 5063    }
 5064
 5065    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5066        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5067            original_indent_columns: Vec::new(),
 5068        });
 5069        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5070    }
 5071
 5072    fn insert_with_autoindent_mode(
 5073        &mut self,
 5074        text: &str,
 5075        autoindent_mode: Option<AutoindentMode>,
 5076        window: &mut Window,
 5077        cx: &mut Context<Self>,
 5078    ) {
 5079        if self.read_only(cx) {
 5080            return;
 5081        }
 5082
 5083        let text: Arc<str> = text.into();
 5084        self.transact(window, cx, |this, window, cx| {
 5085            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5086            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5087                let anchors = {
 5088                    let snapshot = buffer.read(cx);
 5089                    old_selections
 5090                        .iter()
 5091                        .map(|s| {
 5092                            let anchor = snapshot.anchor_after(s.head());
 5093                            s.map(|_| anchor)
 5094                        })
 5095                        .collect::<Vec<_>>()
 5096                };
 5097                buffer.edit(
 5098                    old_selections
 5099                        .iter()
 5100                        .map(|s| (s.start..s.end, text.clone())),
 5101                    autoindent_mode,
 5102                    cx,
 5103                );
 5104                anchors
 5105            });
 5106
 5107            this.change_selections(Default::default(), window, cx, |s| {
 5108                s.select_anchors(selection_anchors);
 5109            });
 5110
 5111            cx.notify();
 5112        });
 5113    }
 5114
 5115    fn trigger_completion_on_input(
 5116        &mut self,
 5117        text: &str,
 5118        trigger_in_words: bool,
 5119        window: &mut Window,
 5120        cx: &mut Context<Self>,
 5121    ) {
 5122        let completions_source = self
 5123            .context_menu
 5124            .borrow()
 5125            .as_ref()
 5126            .and_then(|menu| match menu {
 5127                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5128                CodeContextMenu::CodeActions(_) => None,
 5129            });
 5130
 5131        match completions_source {
 5132            Some(CompletionsMenuSource::Words { .. }) => {
 5133                self.open_or_update_completions_menu(
 5134                    Some(CompletionsMenuSource::Words {
 5135                        ignore_threshold: false,
 5136                    }),
 5137                    None,
 5138                    trigger_in_words,
 5139                    window,
 5140                    cx,
 5141                );
 5142            }
 5143            _ => self.open_or_update_completions_menu(
 5144                None,
 5145                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5146                true,
 5147                window,
 5148                cx,
 5149            ),
 5150        }
 5151    }
 5152
 5153    /// If any empty selections is touching the start of its innermost containing autoclose
 5154    /// region, expand it to select the brackets.
 5155    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5156        let selections = self
 5157            .selections
 5158            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5159        let buffer = self.buffer.read(cx).read(cx);
 5160        let new_selections = self
 5161            .selections_with_autoclose_regions(selections, &buffer)
 5162            .map(|(mut selection, region)| {
 5163                if !selection.is_empty() {
 5164                    return selection;
 5165                }
 5166
 5167                if let Some(region) = region {
 5168                    let mut range = region.range.to_offset(&buffer);
 5169                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5170                        range.start -= region.pair.start.len();
 5171                        if buffer.contains_str_at(range.start, &region.pair.start)
 5172                            && buffer.contains_str_at(range.end, &region.pair.end)
 5173                        {
 5174                            range.end += region.pair.end.len();
 5175                            selection.start = range.start;
 5176                            selection.end = range.end;
 5177
 5178                            return selection;
 5179                        }
 5180                    }
 5181                }
 5182
 5183                let always_treat_brackets_as_autoclosed = buffer
 5184                    .language_settings_at(selection.start, cx)
 5185                    .always_treat_brackets_as_autoclosed;
 5186
 5187                if !always_treat_brackets_as_autoclosed {
 5188                    return selection;
 5189                }
 5190
 5191                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5192                    for (pair, enabled) in scope.brackets() {
 5193                        if !enabled || !pair.close {
 5194                            continue;
 5195                        }
 5196
 5197                        if buffer.contains_str_at(selection.start, &pair.end) {
 5198                            let pair_start_len = pair.start.len();
 5199                            if buffer.contains_str_at(
 5200                                selection.start.saturating_sub_usize(pair_start_len),
 5201                                &pair.start,
 5202                            ) {
 5203                                selection.start -= pair_start_len;
 5204                                selection.end += pair.end.len();
 5205
 5206                                return selection;
 5207                            }
 5208                        }
 5209                    }
 5210                }
 5211
 5212                selection
 5213            })
 5214            .collect();
 5215
 5216        drop(buffer);
 5217        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5218            selections.select(new_selections)
 5219        });
 5220    }
 5221
 5222    /// Iterate the given selections, and for each one, find the smallest surrounding
 5223    /// autoclose region. This uses the ordering of the selections and the autoclose
 5224    /// regions to avoid repeated comparisons.
 5225    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5226        &'a self,
 5227        selections: impl IntoIterator<Item = Selection<D>>,
 5228        buffer: &'a MultiBufferSnapshot,
 5229    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5230        let mut i = 0;
 5231        let mut regions = self.autoclose_regions.as_slice();
 5232        selections.into_iter().map(move |selection| {
 5233            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5234
 5235            let mut enclosing = None;
 5236            while let Some(pair_state) = regions.get(i) {
 5237                if pair_state.range.end.to_offset(buffer) < range.start {
 5238                    regions = &regions[i + 1..];
 5239                    i = 0;
 5240                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5241                    break;
 5242                } else {
 5243                    if pair_state.selection_id == selection.id {
 5244                        enclosing = Some(pair_state);
 5245                    }
 5246                    i += 1;
 5247                }
 5248            }
 5249
 5250            (selection, enclosing)
 5251        })
 5252    }
 5253
 5254    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5255    fn invalidate_autoclose_regions(
 5256        &mut self,
 5257        mut selections: &[Selection<Anchor>],
 5258        buffer: &MultiBufferSnapshot,
 5259    ) {
 5260        self.autoclose_regions.retain(|state| {
 5261            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5262                return false;
 5263            }
 5264
 5265            let mut i = 0;
 5266            while let Some(selection) = selections.get(i) {
 5267                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5268                    selections = &selections[1..];
 5269                    continue;
 5270                }
 5271                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5272                    break;
 5273                }
 5274                if selection.id == state.selection_id {
 5275                    return true;
 5276                } else {
 5277                    i += 1;
 5278                }
 5279            }
 5280            false
 5281        });
 5282    }
 5283
 5284    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5285        let offset = position.to_offset(buffer);
 5286        let (word_range, kind) =
 5287            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5288        if offset > word_range.start && kind == Some(CharKind::Word) {
 5289            Some(
 5290                buffer
 5291                    .text_for_range(word_range.start..offset)
 5292                    .collect::<String>(),
 5293            )
 5294        } else {
 5295            None
 5296        }
 5297    }
 5298
 5299    pub fn visible_excerpts(
 5300        &self,
 5301        lsp_related_only: bool,
 5302        cx: &mut Context<Editor>,
 5303    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5304        let project = self.project().cloned();
 5305        let multi_buffer = self.buffer().read(cx);
 5306        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5307        let multi_buffer_visible_start = self
 5308            .scroll_manager
 5309            .anchor()
 5310            .anchor
 5311            .to_point(&multi_buffer_snapshot);
 5312        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5313            multi_buffer_visible_start
 5314                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5315            Bias::Left,
 5316        );
 5317        multi_buffer_snapshot
 5318            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5319            .into_iter()
 5320            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5321            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5322                if !lsp_related_only {
 5323                    return Some((
 5324                        excerpt_id,
 5325                        (
 5326                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5327                            buffer.version().clone(),
 5328                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5329                        ),
 5330                    ));
 5331                }
 5332
 5333                let project = project.as_ref()?.read(cx);
 5334                let buffer_file = project::File::from_dyn(buffer.file())?;
 5335                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5336                let worktree_entry = buffer_worktree
 5337                    .read(cx)
 5338                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5339                if worktree_entry.is_ignored {
 5340                    None
 5341                } else {
 5342                    Some((
 5343                        excerpt_id,
 5344                        (
 5345                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5346                            buffer.version().clone(),
 5347                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5348                        ),
 5349                    ))
 5350                }
 5351            })
 5352            .collect()
 5353    }
 5354
 5355    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5356        TextLayoutDetails {
 5357            text_system: window.text_system().clone(),
 5358            editor_style: self.style.clone().unwrap(),
 5359            rem_size: window.rem_size(),
 5360            scroll_anchor: self.scroll_manager.anchor(),
 5361            visible_rows: self.visible_line_count(),
 5362            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5363        }
 5364    }
 5365
 5366    fn trigger_on_type_formatting(
 5367        &self,
 5368        input: String,
 5369        window: &mut Window,
 5370        cx: &mut Context<Self>,
 5371    ) -> Option<Task<Result<()>>> {
 5372        if input.chars().count() != 1 {
 5373            return None;
 5374        }
 5375
 5376        let project = self.project()?;
 5377        let position = self.selections.newest_anchor().head();
 5378        let (buffer, buffer_position) = self
 5379            .buffer
 5380            .read(cx)
 5381            .text_anchor_for_position(position, cx)?;
 5382
 5383        let settings = language_settings::language_settings(
 5384            buffer
 5385                .read(cx)
 5386                .language_at(buffer_position)
 5387                .map(|l| l.name()),
 5388            buffer.read(cx).file(),
 5389            cx,
 5390        );
 5391        if !settings.use_on_type_format {
 5392            return None;
 5393        }
 5394
 5395        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5396        // hence we do LSP request & edit on host side only — add formats to host's history.
 5397        let push_to_lsp_host_history = true;
 5398        // If this is not the host, append its history with new edits.
 5399        let push_to_client_history = project.read(cx).is_via_collab();
 5400
 5401        let on_type_formatting = project.update(cx, |project, cx| {
 5402            project.on_type_format(
 5403                buffer.clone(),
 5404                buffer_position,
 5405                input,
 5406                push_to_lsp_host_history,
 5407                cx,
 5408            )
 5409        });
 5410        Some(cx.spawn_in(window, async move |editor, cx| {
 5411            if let Some(transaction) = on_type_formatting.await? {
 5412                if push_to_client_history {
 5413                    buffer
 5414                        .update(cx, |buffer, _| {
 5415                            buffer.push_transaction(transaction, Instant::now());
 5416                            buffer.finalize_last_transaction();
 5417                        })
 5418                        .ok();
 5419                }
 5420                editor.update(cx, |editor, cx| {
 5421                    editor.refresh_document_highlights(cx);
 5422                })?;
 5423            }
 5424            Ok(())
 5425        }))
 5426    }
 5427
 5428    pub fn show_word_completions(
 5429        &mut self,
 5430        _: &ShowWordCompletions,
 5431        window: &mut Window,
 5432        cx: &mut Context<Self>,
 5433    ) {
 5434        self.open_or_update_completions_menu(
 5435            Some(CompletionsMenuSource::Words {
 5436                ignore_threshold: true,
 5437            }),
 5438            None,
 5439            false,
 5440            window,
 5441            cx,
 5442        );
 5443    }
 5444
 5445    pub fn show_completions(
 5446        &mut self,
 5447        _: &ShowCompletions,
 5448        window: &mut Window,
 5449        cx: &mut Context<Self>,
 5450    ) {
 5451        self.open_or_update_completions_menu(None, None, false, window, cx);
 5452    }
 5453
 5454    fn open_or_update_completions_menu(
 5455        &mut self,
 5456        requested_source: Option<CompletionsMenuSource>,
 5457        trigger: Option<String>,
 5458        trigger_in_words: bool,
 5459        window: &mut Window,
 5460        cx: &mut Context<Self>,
 5461    ) {
 5462        if self.pending_rename.is_some() {
 5463            return;
 5464        }
 5465
 5466        let completions_source = self
 5467            .context_menu
 5468            .borrow()
 5469            .as_ref()
 5470            .and_then(|menu| match menu {
 5471                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5472                CodeContextMenu::CodeActions(_) => None,
 5473            });
 5474
 5475        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5476
 5477        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5478        // inserted and selected. To handle that case, the start of the selection is used so that
 5479        // the menu starts with all choices.
 5480        let position = self
 5481            .selections
 5482            .newest_anchor()
 5483            .start
 5484            .bias_right(&multibuffer_snapshot);
 5485        if position.diff_base_anchor.is_some() {
 5486            return;
 5487        }
 5488        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5489        let Some(buffer) = buffer_position
 5490            .text_anchor
 5491            .buffer_id
 5492            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5493        else {
 5494            return;
 5495        };
 5496        let buffer_snapshot = buffer.read(cx).snapshot();
 5497
 5498        let menu_is_open = matches!(
 5499            self.context_menu.borrow().as_ref(),
 5500            Some(CodeContextMenu::Completions(_))
 5501        );
 5502
 5503        let language = buffer_snapshot
 5504            .language_at(buffer_position.text_anchor)
 5505            .map(|language| language.name());
 5506
 5507        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5508        let completion_settings = language_settings.completions.clone();
 5509
 5510        let show_completions_on_input = self
 5511            .show_completions_on_input_override
 5512            .unwrap_or(language_settings.show_completions_on_input);
 5513        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5514            return;
 5515        }
 5516
 5517        let query: Option<Arc<String>> =
 5518            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5519                .map(|query| query.into());
 5520
 5521        drop(multibuffer_snapshot);
 5522
 5523        // Hide the current completions menu when query is empty. Without this, cached
 5524        // completions from before the trigger char may be reused (#32774).
 5525        if query.is_none() && menu_is_open {
 5526            self.hide_context_menu(window, cx);
 5527        }
 5528
 5529        let mut ignore_word_threshold = false;
 5530        let provider = match requested_source {
 5531            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5532            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5533                ignore_word_threshold = ignore_threshold;
 5534                None
 5535            }
 5536            Some(CompletionsMenuSource::SnippetChoices)
 5537            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5538                log::error!("bug: SnippetChoices requested_source is not handled");
 5539                None
 5540            }
 5541        };
 5542
 5543        let sort_completions = provider
 5544            .as_ref()
 5545            .is_some_and(|provider| provider.sort_completions());
 5546
 5547        let filter_completions = provider
 5548            .as_ref()
 5549            .is_none_or(|provider| provider.filter_completions());
 5550
 5551        let was_snippets_only = matches!(
 5552            completions_source,
 5553            Some(CompletionsMenuSource::SnippetsOnly)
 5554        );
 5555
 5556        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5557            if filter_completions {
 5558                menu.filter(
 5559                    query.clone().unwrap_or_default(),
 5560                    buffer_position.text_anchor,
 5561                    &buffer,
 5562                    provider.clone(),
 5563                    window,
 5564                    cx,
 5565                );
 5566            }
 5567            // When `is_incomplete` is false, no need to re-query completions when the current query
 5568            // is a suffix of the initial query.
 5569            let was_complete = !menu.is_incomplete;
 5570            if was_complete && !was_snippets_only {
 5571                // If the new query is a suffix of the old query (typing more characters) and
 5572                // the previous result was complete, the existing completions can be filtered.
 5573                //
 5574                // Note that snippet completions are always complete.
 5575                let query_matches = match (&menu.initial_query, &query) {
 5576                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5577                    (None, _) => true,
 5578                    _ => false,
 5579                };
 5580                if query_matches {
 5581                    let position_matches = if menu.initial_position == position {
 5582                        true
 5583                    } else {
 5584                        let snapshot = self.buffer.read(cx).read(cx);
 5585                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5586                    };
 5587                    if position_matches {
 5588                        return;
 5589                    }
 5590                }
 5591            }
 5592        };
 5593
 5594        let Anchor {
 5595            excerpt_id: buffer_excerpt_id,
 5596            text_anchor: buffer_position,
 5597            ..
 5598        } = buffer_position;
 5599
 5600        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5601            buffer_snapshot.surrounding_word(buffer_position, None)
 5602        {
 5603            let word_to_exclude = buffer_snapshot
 5604                .text_for_range(word_range.clone())
 5605                .collect::<String>();
 5606            (
 5607                buffer_snapshot.anchor_before(word_range.start)
 5608                    ..buffer_snapshot.anchor_after(buffer_position),
 5609                Some(word_to_exclude),
 5610            )
 5611        } else {
 5612            (buffer_position..buffer_position, None)
 5613        };
 5614
 5615        let show_completion_documentation = buffer_snapshot
 5616            .settings_at(buffer_position, cx)
 5617            .show_completion_documentation;
 5618
 5619        // The document can be large, so stay in reasonable bounds when searching for words,
 5620        // otherwise completion pop-up might be slow to appear.
 5621        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5622        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5623        let min_word_search = buffer_snapshot.clip_point(
 5624            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5625            Bias::Left,
 5626        );
 5627        let max_word_search = buffer_snapshot.clip_point(
 5628            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5629            Bias::Right,
 5630        );
 5631        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5632            ..buffer_snapshot.point_to_offset(max_word_search);
 5633
 5634        let skip_digits = query
 5635            .as_ref()
 5636            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5637
 5638        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5639            trigger.as_ref().is_none_or(|trigger| {
 5640                provider.is_completion_trigger(
 5641                    &buffer,
 5642                    position.text_anchor,
 5643                    trigger,
 5644                    trigger_in_words,
 5645                    cx,
 5646                )
 5647            })
 5648        });
 5649
 5650        let provider_responses = if let Some(provider) = &provider
 5651            && load_provider_completions
 5652        {
 5653            let trigger_character =
 5654                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5655            let completion_context = CompletionContext {
 5656                trigger_kind: match &trigger_character {
 5657                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5658                    None => CompletionTriggerKind::INVOKED,
 5659                },
 5660                trigger_character,
 5661            };
 5662
 5663            provider.completions(
 5664                buffer_excerpt_id,
 5665                &buffer,
 5666                buffer_position,
 5667                completion_context,
 5668                window,
 5669                cx,
 5670            )
 5671        } else {
 5672            Task::ready(Ok(Vec::new()))
 5673        };
 5674
 5675        let load_word_completions = if !self.word_completions_enabled {
 5676            false
 5677        } else if requested_source
 5678            == Some(CompletionsMenuSource::Words {
 5679                ignore_threshold: true,
 5680            })
 5681        {
 5682            true
 5683        } else {
 5684            load_provider_completions
 5685                && completion_settings.words != WordsCompletionMode::Disabled
 5686                && (ignore_word_threshold || {
 5687                    let words_min_length = completion_settings.words_min_length;
 5688                    // check whether word has at least `words_min_length` characters
 5689                    let query_chars = query.iter().flat_map(|q| q.chars());
 5690                    query_chars.take(words_min_length).count() == words_min_length
 5691                })
 5692        };
 5693
 5694        let mut words = if load_word_completions {
 5695            cx.background_spawn({
 5696                let buffer_snapshot = buffer_snapshot.clone();
 5697                async move {
 5698                    buffer_snapshot.words_in_range(WordsQuery {
 5699                        fuzzy_contents: None,
 5700                        range: word_search_range,
 5701                        skip_digits,
 5702                    })
 5703                }
 5704            })
 5705        } else {
 5706            Task::ready(BTreeMap::default())
 5707        };
 5708
 5709        let snippets = if let Some(provider) = &provider
 5710            && provider.show_snippets()
 5711            && let Some(project) = self.project()
 5712        {
 5713            let char_classifier = buffer_snapshot
 5714                .char_classifier_at(buffer_position)
 5715                .scope_context(Some(CharScopeContext::Completion));
 5716            project.update(cx, |project, cx| {
 5717                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5718            })
 5719        } else {
 5720            Task::ready(Ok(CompletionResponse {
 5721                completions: Vec::new(),
 5722                display_options: Default::default(),
 5723                is_incomplete: false,
 5724            }))
 5725        };
 5726
 5727        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5728
 5729        let id = post_inc(&mut self.next_completion_id);
 5730        let task = cx.spawn_in(window, async move |editor, cx| {
 5731            let Ok(()) = editor.update(cx, |this, _| {
 5732                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5733            }) else {
 5734                return;
 5735            };
 5736
 5737            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5738            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5739            let mut completions = Vec::new();
 5740            let mut is_incomplete = false;
 5741            let mut display_options: Option<CompletionDisplayOptions> = None;
 5742            if let Some(provider_responses) = provider_responses.await.log_err()
 5743                && !provider_responses.is_empty()
 5744            {
 5745                for response in provider_responses {
 5746                    completions.extend(response.completions);
 5747                    is_incomplete = is_incomplete || response.is_incomplete;
 5748                    match display_options.as_mut() {
 5749                        None => {
 5750                            display_options = Some(response.display_options);
 5751                        }
 5752                        Some(options) => options.merge(&response.display_options),
 5753                    }
 5754                }
 5755                if completion_settings.words == WordsCompletionMode::Fallback {
 5756                    words = Task::ready(BTreeMap::default());
 5757                }
 5758            }
 5759            let display_options = display_options.unwrap_or_default();
 5760
 5761            let mut words = words.await;
 5762            if let Some(word_to_exclude) = &word_to_exclude {
 5763                words.remove(word_to_exclude);
 5764            }
 5765            for lsp_completion in &completions {
 5766                words.remove(&lsp_completion.new_text);
 5767            }
 5768            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5769                replace_range: word_replace_range.clone(),
 5770                new_text: word.clone(),
 5771                label: CodeLabel::plain(word, None),
 5772                match_start: None,
 5773                snippet_deduplication_key: None,
 5774                icon_path: None,
 5775                documentation: None,
 5776                source: CompletionSource::BufferWord {
 5777                    word_range,
 5778                    resolved: false,
 5779                },
 5780                insert_text_mode: Some(InsertTextMode::AS_IS),
 5781                confirm: None,
 5782            }));
 5783
 5784            completions.extend(
 5785                snippets
 5786                    .await
 5787                    .into_iter()
 5788                    .flat_map(|response| response.completions),
 5789            );
 5790
 5791            let menu = if completions.is_empty() {
 5792                None
 5793            } else {
 5794                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5795                    let languages = editor
 5796                        .workspace
 5797                        .as_ref()
 5798                        .and_then(|(workspace, _)| workspace.upgrade())
 5799                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5800                    let menu = CompletionsMenu::new(
 5801                        id,
 5802                        requested_source.unwrap_or(if load_provider_completions {
 5803                            CompletionsMenuSource::Normal
 5804                        } else {
 5805                            CompletionsMenuSource::SnippetsOnly
 5806                        }),
 5807                        sort_completions,
 5808                        show_completion_documentation,
 5809                        position,
 5810                        query.clone(),
 5811                        is_incomplete,
 5812                        buffer.clone(),
 5813                        completions.into(),
 5814                        editor
 5815                            .context_menu()
 5816                            .borrow_mut()
 5817                            .as_ref()
 5818                            .map(|menu| menu.primary_scroll_handle()),
 5819                        display_options,
 5820                        snippet_sort_order,
 5821                        languages,
 5822                        language,
 5823                        cx,
 5824                    );
 5825
 5826                    let query = if filter_completions { query } else { None };
 5827                    let matches_task = menu.do_async_filtering(
 5828                        query.unwrap_or_default(),
 5829                        buffer_position,
 5830                        &buffer,
 5831                        cx,
 5832                    );
 5833                    (menu, matches_task)
 5834                }) else {
 5835                    return;
 5836                };
 5837
 5838                let matches = matches_task.await;
 5839
 5840                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5841                    // Newer menu already set, so exit.
 5842                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5843                        editor.context_menu.borrow().as_ref()
 5844                        && prev_menu.id > id
 5845                    {
 5846                        return;
 5847                    };
 5848
 5849                    // Only valid to take prev_menu because either the new menu is immediately set
 5850                    // below, or the menu is hidden.
 5851                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5852                        editor.context_menu.borrow_mut().take()
 5853                    {
 5854                        let position_matches =
 5855                            if prev_menu.initial_position == menu.initial_position {
 5856                                true
 5857                            } else {
 5858                                let snapshot = editor.buffer.read(cx).read(cx);
 5859                                prev_menu.initial_position.to_offset(&snapshot)
 5860                                    == menu.initial_position.to_offset(&snapshot)
 5861                            };
 5862                        if position_matches {
 5863                            // Preserve markdown cache before `set_filter_results` because it will
 5864                            // try to populate the documentation cache.
 5865                            menu.preserve_markdown_cache(prev_menu);
 5866                        }
 5867                    };
 5868
 5869                    menu.set_filter_results(matches, provider, window, cx);
 5870                }) else {
 5871                    return;
 5872                };
 5873
 5874                menu.visible().then_some(menu)
 5875            };
 5876
 5877            editor
 5878                .update_in(cx, |editor, window, cx| {
 5879                    if editor.focus_handle.is_focused(window)
 5880                        && let Some(menu) = menu
 5881                    {
 5882                        *editor.context_menu.borrow_mut() =
 5883                            Some(CodeContextMenu::Completions(menu));
 5884
 5885                        crate::hover_popover::hide_hover(editor, cx);
 5886                        if editor.show_edit_predictions_in_menu() {
 5887                            editor.update_visible_edit_prediction(window, cx);
 5888                        } else {
 5889                            editor.discard_edit_prediction(false, cx);
 5890                        }
 5891
 5892                        cx.notify();
 5893                        return;
 5894                    }
 5895
 5896                    if editor.completion_tasks.len() <= 1 {
 5897                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5898                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5899                        // If it was already hidden and we don't show edit predictions in the menu,
 5900                        // we should also show the edit prediction when available.
 5901                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5902                            editor.update_visible_edit_prediction(window, cx);
 5903                        }
 5904                    }
 5905                })
 5906                .ok();
 5907        });
 5908
 5909        self.completion_tasks.push((id, task));
 5910    }
 5911
 5912    #[cfg(feature = "test-support")]
 5913    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5914        let menu = self.context_menu.borrow();
 5915        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5916            let completions = menu.completions.borrow();
 5917            Some(completions.to_vec())
 5918        } else {
 5919            None
 5920        }
 5921    }
 5922
 5923    pub fn with_completions_menu_matching_id<R>(
 5924        &self,
 5925        id: CompletionId,
 5926        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5927    ) -> R {
 5928        let mut context_menu = self.context_menu.borrow_mut();
 5929        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5930            return f(None);
 5931        };
 5932        if completions_menu.id != id {
 5933            return f(None);
 5934        }
 5935        f(Some(completions_menu))
 5936    }
 5937
 5938    pub fn confirm_completion(
 5939        &mut self,
 5940        action: &ConfirmCompletion,
 5941        window: &mut Window,
 5942        cx: &mut Context<Self>,
 5943    ) -> Option<Task<Result<()>>> {
 5944        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5945        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5946    }
 5947
 5948    pub fn confirm_completion_insert(
 5949        &mut self,
 5950        _: &ConfirmCompletionInsert,
 5951        window: &mut Window,
 5952        cx: &mut Context<Self>,
 5953    ) -> Option<Task<Result<()>>> {
 5954        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5955        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5956    }
 5957
 5958    pub fn confirm_completion_replace(
 5959        &mut self,
 5960        _: &ConfirmCompletionReplace,
 5961        window: &mut Window,
 5962        cx: &mut Context<Self>,
 5963    ) -> Option<Task<Result<()>>> {
 5964        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5965        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5966    }
 5967
 5968    pub fn compose_completion(
 5969        &mut self,
 5970        action: &ComposeCompletion,
 5971        window: &mut Window,
 5972        cx: &mut Context<Self>,
 5973    ) -> Option<Task<Result<()>>> {
 5974        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5975        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5976    }
 5977
 5978    fn do_completion(
 5979        &mut self,
 5980        item_ix: Option<usize>,
 5981        intent: CompletionIntent,
 5982        window: &mut Window,
 5983        cx: &mut Context<Editor>,
 5984    ) -> Option<Task<Result<()>>> {
 5985        use language::ToOffset as _;
 5986
 5987        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5988        else {
 5989            return None;
 5990        };
 5991
 5992        let candidate_id = {
 5993            let entries = completions_menu.entries.borrow();
 5994            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5995            if self.show_edit_predictions_in_menu() {
 5996                self.discard_edit_prediction(true, cx);
 5997            }
 5998            mat.candidate_id
 5999        };
 6000
 6001        let completion = completions_menu
 6002            .completions
 6003            .borrow()
 6004            .get(candidate_id)?
 6005            .clone();
 6006        cx.stop_propagation();
 6007
 6008        let buffer_handle = completions_menu.buffer.clone();
 6009
 6010        let CompletionEdit {
 6011            new_text,
 6012            snippet,
 6013            replace_range,
 6014        } = process_completion_for_edit(
 6015            &completion,
 6016            intent,
 6017            &buffer_handle,
 6018            &completions_menu.initial_position.text_anchor,
 6019            cx,
 6020        );
 6021
 6022        let buffer = buffer_handle.read(cx);
 6023        let snapshot = self.buffer.read(cx).snapshot(cx);
 6024        let newest_anchor = self.selections.newest_anchor();
 6025        let replace_range_multibuffer = {
 6026            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6027            excerpt.map_range_from_buffer(replace_range.clone())
 6028        };
 6029        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6030            return None;
 6031        }
 6032
 6033        let old_text = buffer
 6034            .text_for_range(replace_range.clone())
 6035            .collect::<String>();
 6036        let lookbehind = newest_anchor
 6037            .start
 6038            .text_anchor
 6039            .to_offset(buffer)
 6040            .saturating_sub(replace_range.start.0);
 6041        let lookahead = replace_range
 6042            .end
 6043            .0
 6044            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6045        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6046        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6047
 6048        let selections = self
 6049            .selections
 6050            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6051        let mut ranges = Vec::new();
 6052        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6053
 6054        for selection in &selections {
 6055            let range = if selection.id == newest_anchor.id {
 6056                replace_range_multibuffer.clone()
 6057            } else {
 6058                let mut range = selection.range();
 6059
 6060                // if prefix is present, don't duplicate it
 6061                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6062                    range.start = range.start.saturating_sub_usize(lookbehind);
 6063
 6064                    // if suffix is also present, mimic the newest cursor and replace it
 6065                    if selection.id != newest_anchor.id
 6066                        && snapshot.contains_str_at(range.end, suffix)
 6067                    {
 6068                        range.end += lookahead;
 6069                    }
 6070                }
 6071                range
 6072            };
 6073
 6074            ranges.push(range.clone());
 6075
 6076            if !self.linked_edit_ranges.is_empty() {
 6077                let start_anchor = snapshot.anchor_before(range.start);
 6078                let end_anchor = snapshot.anchor_after(range.end);
 6079                if let Some(ranges) = self
 6080                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6081                {
 6082                    for (buffer, edits) in ranges {
 6083                        linked_edits
 6084                            .entry(buffer.clone())
 6085                            .or_default()
 6086                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6087                    }
 6088                }
 6089            }
 6090        }
 6091
 6092        let common_prefix_len = old_text
 6093            .chars()
 6094            .zip(new_text.chars())
 6095            .take_while(|(a, b)| a == b)
 6096            .map(|(a, _)| a.len_utf8())
 6097            .sum::<usize>();
 6098
 6099        cx.emit(EditorEvent::InputHandled {
 6100            utf16_range_to_replace: None,
 6101            text: new_text[common_prefix_len..].into(),
 6102        });
 6103
 6104        self.transact(window, cx, |editor, window, cx| {
 6105            if let Some(mut snippet) = snippet {
 6106                snippet.text = new_text.to_string();
 6107                editor
 6108                    .insert_snippet(&ranges, snippet, window, cx)
 6109                    .log_err();
 6110            } else {
 6111                editor.buffer.update(cx, |multi_buffer, cx| {
 6112                    let auto_indent = match completion.insert_text_mode {
 6113                        Some(InsertTextMode::AS_IS) => None,
 6114                        _ => editor.autoindent_mode.clone(),
 6115                    };
 6116                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6117                    multi_buffer.edit(edits, auto_indent, cx);
 6118                });
 6119            }
 6120            for (buffer, edits) in linked_edits {
 6121                buffer.update(cx, |buffer, cx| {
 6122                    let snapshot = buffer.snapshot();
 6123                    let edits = edits
 6124                        .into_iter()
 6125                        .map(|(range, text)| {
 6126                            use text::ToPoint as TP;
 6127                            let end_point = TP::to_point(&range.end, &snapshot);
 6128                            let start_point = TP::to_point(&range.start, &snapshot);
 6129                            (start_point..end_point, text)
 6130                        })
 6131                        .sorted_by_key(|(range, _)| range.start);
 6132                    buffer.edit(edits, None, cx);
 6133                })
 6134            }
 6135
 6136            editor.refresh_edit_prediction(true, false, window, cx);
 6137        });
 6138        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6139
 6140        let show_new_completions_on_confirm = completion
 6141            .confirm
 6142            .as_ref()
 6143            .is_some_and(|confirm| confirm(intent, window, cx));
 6144        if show_new_completions_on_confirm {
 6145            self.open_or_update_completions_menu(None, None, false, window, cx);
 6146        }
 6147
 6148        let provider = self.completion_provider.as_ref()?;
 6149
 6150        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6151        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6152            let CompletionSource::Lsp {
 6153                lsp_completion,
 6154                server_id,
 6155                ..
 6156            } = &completion.source
 6157            else {
 6158                return None;
 6159            };
 6160            let lsp_command = lsp_completion.command.as_ref()?;
 6161            let available_commands = lsp_store
 6162                .read(cx)
 6163                .lsp_server_capabilities
 6164                .get(server_id)
 6165                .and_then(|server_capabilities| {
 6166                    server_capabilities
 6167                        .execute_command_provider
 6168                        .as_ref()
 6169                        .map(|options| options.commands.as_slice())
 6170                })?;
 6171            if available_commands.contains(&lsp_command.command) {
 6172                Some(CodeAction {
 6173                    server_id: *server_id,
 6174                    range: language::Anchor::MIN..language::Anchor::MIN,
 6175                    lsp_action: LspAction::Command(lsp_command.clone()),
 6176                    resolved: false,
 6177                })
 6178            } else {
 6179                None
 6180            }
 6181        });
 6182
 6183        drop(completion);
 6184        let apply_edits = provider.apply_additional_edits_for_completion(
 6185            buffer_handle.clone(),
 6186            completions_menu.completions.clone(),
 6187            candidate_id,
 6188            true,
 6189            cx,
 6190        );
 6191
 6192        let editor_settings = EditorSettings::get_global(cx);
 6193        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6194            // After the code completion is finished, users often want to know what signatures are needed.
 6195            // so we should automatically call signature_help
 6196            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6197        }
 6198
 6199        Some(cx.spawn_in(window, async move |editor, cx| {
 6200            apply_edits.await?;
 6201
 6202            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6203                let title = command.lsp_action.title().to_owned();
 6204                let project_transaction = lsp_store
 6205                    .update(cx, |lsp_store, cx| {
 6206                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6207                    })?
 6208                    .await
 6209                    .context("applying post-completion command")?;
 6210                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6211                    Self::open_project_transaction(
 6212                        &editor,
 6213                        workspace.downgrade(),
 6214                        project_transaction,
 6215                        title,
 6216                        cx,
 6217                    )
 6218                    .await?;
 6219                }
 6220            }
 6221
 6222            Ok(())
 6223        }))
 6224    }
 6225
 6226    pub fn toggle_code_actions(
 6227        &mut self,
 6228        action: &ToggleCodeActions,
 6229        window: &mut Window,
 6230        cx: &mut Context<Self>,
 6231    ) {
 6232        let quick_launch = action.quick_launch;
 6233        let mut context_menu = self.context_menu.borrow_mut();
 6234        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6235            if code_actions.deployed_from == action.deployed_from {
 6236                // Toggle if we're selecting the same one
 6237                *context_menu = None;
 6238                cx.notify();
 6239                return;
 6240            } else {
 6241                // Otherwise, clear it and start a new one
 6242                *context_menu = None;
 6243                cx.notify();
 6244            }
 6245        }
 6246        drop(context_menu);
 6247        let snapshot = self.snapshot(window, cx);
 6248        let deployed_from = action.deployed_from.clone();
 6249        let action = action.clone();
 6250        self.completion_tasks.clear();
 6251        self.discard_edit_prediction(false, cx);
 6252
 6253        let multibuffer_point = match &action.deployed_from {
 6254            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6255                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6256            }
 6257            _ => self
 6258                .selections
 6259                .newest::<Point>(&snapshot.display_snapshot)
 6260                .head(),
 6261        };
 6262        let Some((buffer, buffer_row)) = snapshot
 6263            .buffer_snapshot()
 6264            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6265            .and_then(|(buffer_snapshot, range)| {
 6266                self.buffer()
 6267                    .read(cx)
 6268                    .buffer(buffer_snapshot.remote_id())
 6269                    .map(|buffer| (buffer, range.start.row))
 6270            })
 6271        else {
 6272            return;
 6273        };
 6274        let buffer_id = buffer.read(cx).remote_id();
 6275        let tasks = self
 6276            .tasks
 6277            .get(&(buffer_id, buffer_row))
 6278            .map(|t| Arc::new(t.to_owned()));
 6279
 6280        if !self.focus_handle.is_focused(window) {
 6281            return;
 6282        }
 6283        let project = self.project.clone();
 6284
 6285        let code_actions_task = match deployed_from {
 6286            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6287            _ => self.code_actions(buffer_row, window, cx),
 6288        };
 6289
 6290        let runnable_task = match deployed_from {
 6291            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6292            _ => {
 6293                let mut task_context_task = Task::ready(None);
 6294                if let Some(tasks) = &tasks
 6295                    && let Some(project) = project
 6296                {
 6297                    task_context_task =
 6298                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6299                }
 6300
 6301                cx.spawn_in(window, {
 6302                    let buffer = buffer.clone();
 6303                    async move |editor, cx| {
 6304                        let task_context = task_context_task.await;
 6305
 6306                        let resolved_tasks =
 6307                            tasks
 6308                                .zip(task_context.clone())
 6309                                .map(|(tasks, task_context)| ResolvedTasks {
 6310                                    templates: tasks.resolve(&task_context).collect(),
 6311                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6312                                        multibuffer_point.row,
 6313                                        tasks.column,
 6314                                    )),
 6315                                });
 6316                        let debug_scenarios = editor
 6317                            .update(cx, |editor, cx| {
 6318                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6319                            })?
 6320                            .await;
 6321                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6322                    }
 6323                })
 6324            }
 6325        };
 6326
 6327        cx.spawn_in(window, async move |editor, cx| {
 6328            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6329            let code_actions = code_actions_task.await;
 6330            let spawn_straight_away = quick_launch
 6331                && resolved_tasks
 6332                    .as_ref()
 6333                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6334                && code_actions
 6335                    .as_ref()
 6336                    .is_none_or(|actions| actions.is_empty())
 6337                && debug_scenarios.is_empty();
 6338
 6339            editor.update_in(cx, |editor, window, cx| {
 6340                crate::hover_popover::hide_hover(editor, cx);
 6341                let actions = CodeActionContents::new(
 6342                    resolved_tasks,
 6343                    code_actions,
 6344                    debug_scenarios,
 6345                    task_context.unwrap_or_default(),
 6346                );
 6347
 6348                // Don't show the menu if there are no actions available
 6349                if actions.is_empty() {
 6350                    cx.notify();
 6351                    return Task::ready(Ok(()));
 6352                }
 6353
 6354                *editor.context_menu.borrow_mut() =
 6355                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6356                        buffer,
 6357                        actions,
 6358                        selected_item: Default::default(),
 6359                        scroll_handle: UniformListScrollHandle::default(),
 6360                        deployed_from,
 6361                    }));
 6362                cx.notify();
 6363                if spawn_straight_away
 6364                    && let Some(task) = editor.confirm_code_action(
 6365                        &ConfirmCodeAction { item_ix: Some(0) },
 6366                        window,
 6367                        cx,
 6368                    )
 6369                {
 6370                    return task;
 6371                }
 6372
 6373                Task::ready(Ok(()))
 6374            })
 6375        })
 6376        .detach_and_log_err(cx);
 6377    }
 6378
 6379    fn debug_scenarios(
 6380        &mut self,
 6381        resolved_tasks: &Option<ResolvedTasks>,
 6382        buffer: &Entity<Buffer>,
 6383        cx: &mut App,
 6384    ) -> Task<Vec<task::DebugScenario>> {
 6385        maybe!({
 6386            let project = self.project()?;
 6387            let dap_store = project.read(cx).dap_store();
 6388            let mut scenarios = vec![];
 6389            let resolved_tasks = resolved_tasks.as_ref()?;
 6390            let buffer = buffer.read(cx);
 6391            let language = buffer.language()?;
 6392            let file = buffer.file();
 6393            let debug_adapter = language_settings(language.name().into(), file, cx)
 6394                .debuggers
 6395                .first()
 6396                .map(SharedString::from)
 6397                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6398
 6399            dap_store.update(cx, |dap_store, cx| {
 6400                for (_, task) in &resolved_tasks.templates {
 6401                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6402                        task.original_task().clone(),
 6403                        debug_adapter.clone().into(),
 6404                        task.display_label().to_owned().into(),
 6405                        cx,
 6406                    );
 6407                    scenarios.push(maybe_scenario);
 6408                }
 6409            });
 6410            Some(cx.background_spawn(async move {
 6411                futures::future::join_all(scenarios)
 6412                    .await
 6413                    .into_iter()
 6414                    .flatten()
 6415                    .collect::<Vec<_>>()
 6416            }))
 6417        })
 6418        .unwrap_or_else(|| Task::ready(vec![]))
 6419    }
 6420
 6421    fn code_actions(
 6422        &mut self,
 6423        buffer_row: u32,
 6424        window: &mut Window,
 6425        cx: &mut Context<Self>,
 6426    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6427        let mut task = self.code_actions_task.take();
 6428        cx.spawn_in(window, async move |editor, cx| {
 6429            while let Some(prev_task) = task {
 6430                prev_task.await.log_err();
 6431                task = editor
 6432                    .update(cx, |this, _| this.code_actions_task.take())
 6433                    .ok()?;
 6434            }
 6435
 6436            editor
 6437                .update(cx, |editor, cx| {
 6438                    editor
 6439                        .available_code_actions
 6440                        .clone()
 6441                        .and_then(|(location, code_actions)| {
 6442                            let snapshot = location.buffer.read(cx).snapshot();
 6443                            let point_range = location.range.to_point(&snapshot);
 6444                            let point_range = point_range.start.row..=point_range.end.row;
 6445                            if point_range.contains(&buffer_row) {
 6446                                Some(code_actions)
 6447                            } else {
 6448                                None
 6449                            }
 6450                        })
 6451                })
 6452                .ok()
 6453                .flatten()
 6454        })
 6455    }
 6456
 6457    pub fn confirm_code_action(
 6458        &mut self,
 6459        action: &ConfirmCodeAction,
 6460        window: &mut Window,
 6461        cx: &mut Context<Self>,
 6462    ) -> Option<Task<Result<()>>> {
 6463        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6464
 6465        let actions_menu =
 6466            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6467                menu
 6468            } else {
 6469                return None;
 6470            };
 6471
 6472        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6473        let action = actions_menu.actions.get(action_ix)?;
 6474        let title = action.label();
 6475        let buffer = actions_menu.buffer;
 6476        let workspace = self.workspace()?;
 6477
 6478        match action {
 6479            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6480                workspace.update(cx, |workspace, cx| {
 6481                    workspace.schedule_resolved_task(
 6482                        task_source_kind,
 6483                        resolved_task,
 6484                        false,
 6485                        window,
 6486                        cx,
 6487                    );
 6488
 6489                    Some(Task::ready(Ok(())))
 6490                })
 6491            }
 6492            CodeActionsItem::CodeAction {
 6493                excerpt_id,
 6494                action,
 6495                provider,
 6496            } => {
 6497                let apply_code_action =
 6498                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6499                let workspace = workspace.downgrade();
 6500                Some(cx.spawn_in(window, async move |editor, cx| {
 6501                    let project_transaction = apply_code_action.await?;
 6502                    Self::open_project_transaction(
 6503                        &editor,
 6504                        workspace,
 6505                        project_transaction,
 6506                        title,
 6507                        cx,
 6508                    )
 6509                    .await
 6510                }))
 6511            }
 6512            CodeActionsItem::DebugScenario(scenario) => {
 6513                let context = actions_menu.actions.context;
 6514
 6515                workspace.update(cx, |workspace, cx| {
 6516                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6517                    workspace.start_debug_session(
 6518                        scenario,
 6519                        context,
 6520                        Some(buffer),
 6521                        None,
 6522                        window,
 6523                        cx,
 6524                    );
 6525                });
 6526                Some(Task::ready(Ok(())))
 6527            }
 6528        }
 6529    }
 6530
 6531    fn open_transaction_for_hidden_buffers(
 6532        workspace: Entity<Workspace>,
 6533        transaction: ProjectTransaction,
 6534        title: String,
 6535        window: &mut Window,
 6536        cx: &mut Context<Self>,
 6537    ) {
 6538        if transaction.0.is_empty() {
 6539            return;
 6540        }
 6541
 6542        let edited_buffers_already_open = {
 6543            let other_editors: Vec<Entity<Editor>> = workspace
 6544                .read(cx)
 6545                .panes()
 6546                .iter()
 6547                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6548                .filter(|editor| editor.entity_id() != cx.entity_id())
 6549                .collect();
 6550
 6551            transaction.0.keys().all(|buffer| {
 6552                other_editors.iter().any(|editor| {
 6553                    let multi_buffer = editor.read(cx).buffer();
 6554                    multi_buffer.read(cx).is_singleton()
 6555                        && multi_buffer
 6556                            .read(cx)
 6557                            .as_singleton()
 6558                            .map_or(false, |singleton| {
 6559                                singleton.entity_id() == buffer.entity_id()
 6560                            })
 6561                })
 6562            })
 6563        };
 6564        if !edited_buffers_already_open {
 6565            let workspace = workspace.downgrade();
 6566            cx.defer_in(window, move |_, window, cx| {
 6567                cx.spawn_in(window, async move |editor, cx| {
 6568                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6569                        .await
 6570                        .ok()
 6571                })
 6572                .detach();
 6573            });
 6574        }
 6575    }
 6576
 6577    pub async fn open_project_transaction(
 6578        editor: &WeakEntity<Editor>,
 6579        workspace: WeakEntity<Workspace>,
 6580        transaction: ProjectTransaction,
 6581        title: String,
 6582        cx: &mut AsyncWindowContext,
 6583    ) -> Result<()> {
 6584        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6585        cx.update(|_, cx| {
 6586            entries.sort_unstable_by_key(|(buffer, _)| {
 6587                buffer.read(cx).file().map(|f| f.path().clone())
 6588            });
 6589        })?;
 6590        if entries.is_empty() {
 6591            return Ok(());
 6592        }
 6593
 6594        // If the project transaction's edits are all contained within this editor, then
 6595        // avoid opening a new editor to display them.
 6596
 6597        if let [(buffer, transaction)] = &*entries {
 6598            let excerpt = editor.update(cx, |editor, cx| {
 6599                editor
 6600                    .buffer()
 6601                    .read(cx)
 6602                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6603            })?;
 6604            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6605                && excerpted_buffer == *buffer
 6606            {
 6607                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6608                    let excerpt_range = excerpt_range.to_offset(buffer);
 6609                    buffer
 6610                        .edited_ranges_for_transaction::<usize>(transaction)
 6611                        .all(|range| {
 6612                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6613                        })
 6614                })?;
 6615
 6616                if all_edits_within_excerpt {
 6617                    return Ok(());
 6618                }
 6619            }
 6620        }
 6621
 6622        let mut ranges_to_highlight = Vec::new();
 6623        let excerpt_buffer = cx.new(|cx| {
 6624            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6625            for (buffer_handle, transaction) in &entries {
 6626                let edited_ranges = buffer_handle
 6627                    .read(cx)
 6628                    .edited_ranges_for_transaction::<Point>(transaction)
 6629                    .collect::<Vec<_>>();
 6630                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6631                    PathKey::for_buffer(buffer_handle, cx),
 6632                    buffer_handle.clone(),
 6633                    edited_ranges,
 6634                    multibuffer_context_lines(cx),
 6635                    cx,
 6636                );
 6637
 6638                ranges_to_highlight.extend(ranges);
 6639            }
 6640            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6641            multibuffer
 6642        })?;
 6643
 6644        workspace.update_in(cx, |workspace, window, cx| {
 6645            let project = workspace.project().clone();
 6646            let editor =
 6647                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6648            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6649            editor.update(cx, |editor, cx| {
 6650                editor.highlight_background::<Self>(
 6651                    &ranges_to_highlight,
 6652                    |_, theme| theme.colors().editor_highlighted_line_background,
 6653                    cx,
 6654                );
 6655            });
 6656        })?;
 6657
 6658        Ok(())
 6659    }
 6660
 6661    pub fn clear_code_action_providers(&mut self) {
 6662        self.code_action_providers.clear();
 6663        self.available_code_actions.take();
 6664    }
 6665
 6666    pub fn add_code_action_provider(
 6667        &mut self,
 6668        provider: Rc<dyn CodeActionProvider>,
 6669        window: &mut Window,
 6670        cx: &mut Context<Self>,
 6671    ) {
 6672        if self
 6673            .code_action_providers
 6674            .iter()
 6675            .any(|existing_provider| existing_provider.id() == provider.id())
 6676        {
 6677            return;
 6678        }
 6679
 6680        self.code_action_providers.push(provider);
 6681        self.refresh_code_actions(window, cx);
 6682    }
 6683
 6684    pub fn remove_code_action_provider(
 6685        &mut self,
 6686        id: Arc<str>,
 6687        window: &mut Window,
 6688        cx: &mut Context<Self>,
 6689    ) {
 6690        self.code_action_providers
 6691            .retain(|provider| provider.id() != id);
 6692        self.refresh_code_actions(window, cx);
 6693    }
 6694
 6695    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6696        !self.code_action_providers.is_empty()
 6697            && EditorSettings::get_global(cx).toolbar.code_actions
 6698    }
 6699
 6700    pub fn has_available_code_actions(&self) -> bool {
 6701        self.available_code_actions
 6702            .as_ref()
 6703            .is_some_and(|(_, actions)| !actions.is_empty())
 6704    }
 6705
 6706    fn render_inline_code_actions(
 6707        &self,
 6708        icon_size: ui::IconSize,
 6709        display_row: DisplayRow,
 6710        is_active: bool,
 6711        cx: &mut Context<Self>,
 6712    ) -> AnyElement {
 6713        let show_tooltip = !self.context_menu_visible();
 6714        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6715            .icon_size(icon_size)
 6716            .shape(ui::IconButtonShape::Square)
 6717            .icon_color(ui::Color::Hidden)
 6718            .toggle_state(is_active)
 6719            .when(show_tooltip, |this| {
 6720                this.tooltip({
 6721                    let focus_handle = self.focus_handle.clone();
 6722                    move |_window, cx| {
 6723                        Tooltip::for_action_in(
 6724                            "Toggle Code Actions",
 6725                            &ToggleCodeActions {
 6726                                deployed_from: None,
 6727                                quick_launch: false,
 6728                            },
 6729                            &focus_handle,
 6730                            cx,
 6731                        )
 6732                    }
 6733                })
 6734            })
 6735            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6736                window.focus(&editor.focus_handle(cx), cx);
 6737                editor.toggle_code_actions(
 6738                    &crate::actions::ToggleCodeActions {
 6739                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6740                            display_row,
 6741                        )),
 6742                        quick_launch: false,
 6743                    },
 6744                    window,
 6745                    cx,
 6746                );
 6747            }))
 6748            .into_any_element()
 6749    }
 6750
 6751    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6752        &self.context_menu
 6753    }
 6754
 6755    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6756        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6757            cx.background_executor()
 6758                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6759                .await;
 6760
 6761            let (start_buffer, start, _, end, newest_selection) = this
 6762                .update(cx, |this, cx| {
 6763                    let newest_selection = this.selections.newest_anchor().clone();
 6764                    if newest_selection.head().diff_base_anchor.is_some() {
 6765                        return None;
 6766                    }
 6767                    let display_snapshot = this.display_snapshot(cx);
 6768                    let newest_selection_adjusted =
 6769                        this.selections.newest_adjusted(&display_snapshot);
 6770                    let buffer = this.buffer.read(cx);
 6771
 6772                    let (start_buffer, start) =
 6773                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6774                    let (end_buffer, end) =
 6775                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6776
 6777                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6778                })?
 6779                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6780                .context(
 6781                    "Expected selection to lie in a single buffer when refreshing code actions",
 6782                )?;
 6783            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6784                let providers = this.code_action_providers.clone();
 6785                let tasks = this
 6786                    .code_action_providers
 6787                    .iter()
 6788                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6789                    .collect::<Vec<_>>();
 6790                (providers, tasks)
 6791            })?;
 6792
 6793            let mut actions = Vec::new();
 6794            for (provider, provider_actions) in
 6795                providers.into_iter().zip(future::join_all(tasks).await)
 6796            {
 6797                if let Some(provider_actions) = provider_actions.log_err() {
 6798                    actions.extend(provider_actions.into_iter().map(|action| {
 6799                        AvailableCodeAction {
 6800                            excerpt_id: newest_selection.start.excerpt_id,
 6801                            action,
 6802                            provider: provider.clone(),
 6803                        }
 6804                    }));
 6805                }
 6806            }
 6807
 6808            this.update(cx, |this, cx| {
 6809                this.available_code_actions = if actions.is_empty() {
 6810                    None
 6811                } else {
 6812                    Some((
 6813                        Location {
 6814                            buffer: start_buffer,
 6815                            range: start..end,
 6816                        },
 6817                        actions.into(),
 6818                    ))
 6819                };
 6820                cx.notify();
 6821            })
 6822        }));
 6823    }
 6824
 6825    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6826        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6827            self.show_git_blame_inline = false;
 6828
 6829            self.show_git_blame_inline_delay_task =
 6830                Some(cx.spawn_in(window, async move |this, cx| {
 6831                    cx.background_executor().timer(delay).await;
 6832
 6833                    this.update(cx, |this, cx| {
 6834                        this.show_git_blame_inline = true;
 6835                        cx.notify();
 6836                    })
 6837                    .log_err();
 6838                }));
 6839        }
 6840    }
 6841
 6842    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6843        let snapshot = self.snapshot(window, cx);
 6844        let cursor = self
 6845            .selections
 6846            .newest::<Point>(&snapshot.display_snapshot)
 6847            .head();
 6848        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6849        else {
 6850            return;
 6851        };
 6852
 6853        if self.blame.is_none() {
 6854            self.start_git_blame(true, window, cx);
 6855        }
 6856        let Some(blame) = self.blame.as_ref() else {
 6857            return;
 6858        };
 6859
 6860        let row_info = RowInfo {
 6861            buffer_id: Some(buffer.remote_id()),
 6862            buffer_row: Some(point.row),
 6863            ..Default::default()
 6864        };
 6865        let Some((buffer, blame_entry)) = blame
 6866            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6867            .flatten()
 6868        else {
 6869            return;
 6870        };
 6871
 6872        let anchor = self.selections.newest_anchor().head();
 6873        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 6874        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6875            self.show_blame_popover(
 6876                buffer,
 6877                &blame_entry,
 6878                position + last_bounds.origin,
 6879                true,
 6880                cx,
 6881            );
 6882        };
 6883    }
 6884
 6885    fn show_blame_popover(
 6886        &mut self,
 6887        buffer: BufferId,
 6888        blame_entry: &BlameEntry,
 6889        position: gpui::Point<Pixels>,
 6890        ignore_timeout: bool,
 6891        cx: &mut Context<Self>,
 6892    ) {
 6893        if let Some(state) = &mut self.inline_blame_popover {
 6894            state.hide_task.take();
 6895        } else {
 6896            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6897            let blame_entry = blame_entry.clone();
 6898            let show_task = cx.spawn(async move |editor, cx| {
 6899                if !ignore_timeout {
 6900                    cx.background_executor()
 6901                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6902                        .await;
 6903                }
 6904                editor
 6905                    .update(cx, |editor, cx| {
 6906                        editor.inline_blame_popover_show_task.take();
 6907                        let Some(blame) = editor.blame.as_ref() else {
 6908                            return;
 6909                        };
 6910                        let blame = blame.read(cx);
 6911                        let details = blame.details_for_entry(buffer, &blame_entry);
 6912                        let markdown = cx.new(|cx| {
 6913                            Markdown::new(
 6914                                details
 6915                                    .as_ref()
 6916                                    .map(|message| message.message.clone())
 6917                                    .unwrap_or_default(),
 6918                                None,
 6919                                None,
 6920                                cx,
 6921                            )
 6922                        });
 6923                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6924                            position,
 6925                            hide_task: None,
 6926                            popover_bounds: None,
 6927                            popover_state: InlineBlamePopoverState {
 6928                                scroll_handle: ScrollHandle::new(),
 6929                                commit_message: details,
 6930                                markdown,
 6931                            },
 6932                            keyboard_grace: ignore_timeout,
 6933                        });
 6934                        cx.notify();
 6935                    })
 6936                    .ok();
 6937            });
 6938            self.inline_blame_popover_show_task = Some(show_task);
 6939        }
 6940    }
 6941
 6942    pub fn has_mouse_context_menu(&self) -> bool {
 6943        self.mouse_context_menu.is_some()
 6944    }
 6945
 6946    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6947        self.inline_blame_popover_show_task.take();
 6948        if let Some(state) = &mut self.inline_blame_popover {
 6949            let hide_task = cx.spawn(async move |editor, cx| {
 6950                if !ignore_timeout {
 6951                    cx.background_executor()
 6952                        .timer(std::time::Duration::from_millis(100))
 6953                        .await;
 6954                }
 6955                editor
 6956                    .update(cx, |editor, cx| {
 6957                        editor.inline_blame_popover.take();
 6958                        cx.notify();
 6959                    })
 6960                    .ok();
 6961            });
 6962            state.hide_task = Some(hide_task);
 6963            true
 6964        } else {
 6965            false
 6966        }
 6967    }
 6968
 6969    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6970        if self.pending_rename.is_some() {
 6971            return None;
 6972        }
 6973
 6974        let provider = self.semantics_provider.clone()?;
 6975        let buffer = self.buffer.read(cx);
 6976        let newest_selection = self.selections.newest_anchor().clone();
 6977        let cursor_position = newest_selection.head();
 6978        let (cursor_buffer, cursor_buffer_position) =
 6979            buffer.text_anchor_for_position(cursor_position, cx)?;
 6980        let (tail_buffer, tail_buffer_position) =
 6981            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6982        if cursor_buffer != tail_buffer {
 6983            return None;
 6984        }
 6985
 6986        let snapshot = cursor_buffer.read(cx).snapshot();
 6987        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6988        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6989        if start_word_range != end_word_range {
 6990            self.document_highlights_task.take();
 6991            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6992            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6993            return None;
 6994        }
 6995
 6996        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6997        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6998            cx.background_executor()
 6999                .timer(Duration::from_millis(debounce))
 7000                .await;
 7001
 7002            let highlights = if let Some(highlights) = cx
 7003                .update(|cx| {
 7004                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7005                })
 7006                .ok()
 7007                .flatten()
 7008            {
 7009                highlights.await.log_err()
 7010            } else {
 7011                None
 7012            };
 7013
 7014            if let Some(highlights) = highlights {
 7015                this.update(cx, |this, cx| {
 7016                    if this.pending_rename.is_some() {
 7017                        return;
 7018                    }
 7019
 7020                    let buffer = this.buffer.read(cx);
 7021                    if buffer
 7022                        .text_anchor_for_position(cursor_position, cx)
 7023                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7024                    {
 7025                        return;
 7026                    }
 7027
 7028                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7029                    let mut write_ranges = Vec::new();
 7030                    let mut read_ranges = Vec::new();
 7031                    for highlight in highlights {
 7032                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7033                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7034                        {
 7035                            let start = highlight
 7036                                .range
 7037                                .start
 7038                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7039                            let end = highlight
 7040                                .range
 7041                                .end
 7042                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7043                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7044                                continue;
 7045                            }
 7046
 7047                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7048                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7049                                write_ranges.push(range);
 7050                            } else {
 7051                                read_ranges.push(range);
 7052                            }
 7053                        }
 7054                    }
 7055
 7056                    this.highlight_background::<DocumentHighlightRead>(
 7057                        &read_ranges,
 7058                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7059                        cx,
 7060                    );
 7061                    this.highlight_background::<DocumentHighlightWrite>(
 7062                        &write_ranges,
 7063                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7064                        cx,
 7065                    );
 7066                    cx.notify();
 7067                })
 7068                .log_err();
 7069            }
 7070        }));
 7071        None
 7072    }
 7073
 7074    fn prepare_highlight_query_from_selection(
 7075        &mut self,
 7076        window: &Window,
 7077        cx: &mut Context<Editor>,
 7078    ) -> Option<(String, Range<Anchor>)> {
 7079        if matches!(self.mode, EditorMode::SingleLine) {
 7080            return None;
 7081        }
 7082        if !EditorSettings::get_global(cx).selection_highlight {
 7083            return None;
 7084        }
 7085        if self.selections.count() != 1 || self.selections.line_mode() {
 7086            return None;
 7087        }
 7088        let snapshot = self.snapshot(window, cx);
 7089        let selection = self.selections.newest::<Point>(&snapshot);
 7090        // If the selection spans multiple rows OR it is empty
 7091        if selection.start.row != selection.end.row
 7092            || selection.start.column == selection.end.column
 7093        {
 7094            return None;
 7095        }
 7096        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7097        let query = snapshot
 7098            .buffer_snapshot()
 7099            .text_for_range(selection_anchor_range.clone())
 7100            .collect::<String>();
 7101        if query.trim().is_empty() {
 7102            return None;
 7103        }
 7104        Some((query, selection_anchor_range))
 7105    }
 7106
 7107    #[ztracing::instrument(skip_all)]
 7108    fn update_selection_occurrence_highlights(
 7109        &mut self,
 7110        query_text: String,
 7111        query_range: Range<Anchor>,
 7112        multi_buffer_range_to_query: Range<Point>,
 7113        use_debounce: bool,
 7114        window: &mut Window,
 7115        cx: &mut Context<Editor>,
 7116    ) -> Task<()> {
 7117        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7118        cx.spawn_in(window, async move |editor, cx| {
 7119            if use_debounce {
 7120                cx.background_executor()
 7121                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7122                    .await;
 7123            }
 7124            let match_task = cx.background_spawn(async move {
 7125                let buffer_ranges = multi_buffer_snapshot
 7126                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7127                    .into_iter()
 7128                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7129                let mut match_ranges = Vec::new();
 7130                let Ok(regex) = project::search::SearchQuery::text(
 7131                    query_text.clone(),
 7132                    false,
 7133                    false,
 7134                    false,
 7135                    Default::default(),
 7136                    Default::default(),
 7137                    false,
 7138                    None,
 7139                ) else {
 7140                    return Vec::default();
 7141                };
 7142                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7143                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7144                    match_ranges.extend(
 7145                        regex
 7146                            .search(
 7147                                buffer_snapshot,
 7148                                Some(search_range.start.0..search_range.end.0),
 7149                            )
 7150                            .await
 7151                            .into_iter()
 7152                            .filter_map(|match_range| {
 7153                                let match_start = buffer_snapshot
 7154                                    .anchor_after(search_range.start + match_range.start);
 7155                                let match_end = buffer_snapshot
 7156                                    .anchor_before(search_range.start + match_range.end);
 7157                                let match_anchor_range =
 7158                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7159                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7160                            }),
 7161                    );
 7162                }
 7163                match_ranges
 7164            });
 7165            let match_ranges = match_task.await;
 7166            editor
 7167                .update_in(cx, |editor, _, cx| {
 7168                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7169                    if !match_ranges.is_empty() {
 7170                        editor.highlight_background::<SelectedTextHighlight>(
 7171                            &match_ranges,
 7172                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7173                            cx,
 7174                        )
 7175                    }
 7176                })
 7177                .log_err();
 7178        })
 7179    }
 7180
 7181    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7182        struct NewlineFold;
 7183        let type_id = std::any::TypeId::of::<NewlineFold>();
 7184        if !self.mode.is_single_line() {
 7185            return;
 7186        }
 7187        let snapshot = self.snapshot(window, cx);
 7188        if snapshot.buffer_snapshot().max_point().row == 0 {
 7189            return;
 7190        }
 7191        let task = cx.background_spawn(async move {
 7192            let new_newlines = snapshot
 7193                .buffer_chars_at(MultiBufferOffset(0))
 7194                .filter_map(|(c, i)| {
 7195                    if c == '\n' {
 7196                        Some(
 7197                            snapshot.buffer_snapshot().anchor_after(i)
 7198                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7199                        )
 7200                    } else {
 7201                        None
 7202                    }
 7203                })
 7204                .collect::<Vec<_>>();
 7205            let existing_newlines = snapshot
 7206                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7207                .filter_map(|fold| {
 7208                    if fold.placeholder.type_tag == Some(type_id) {
 7209                        Some(fold.range.start..fold.range.end)
 7210                    } else {
 7211                        None
 7212                    }
 7213                })
 7214                .collect::<Vec<_>>();
 7215
 7216            (new_newlines, existing_newlines)
 7217        });
 7218        self.folding_newlines = cx.spawn(async move |this, cx| {
 7219            let (new_newlines, existing_newlines) = task.await;
 7220            if new_newlines == existing_newlines {
 7221                return;
 7222            }
 7223            let placeholder = FoldPlaceholder {
 7224                render: Arc::new(move |_, _, cx| {
 7225                    div()
 7226                        .bg(cx.theme().status().hint_background)
 7227                        .border_b_1()
 7228                        .size_full()
 7229                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7230                        .border_color(cx.theme().status().hint)
 7231                        .child("\\n")
 7232                        .into_any()
 7233                }),
 7234                constrain_width: false,
 7235                merge_adjacent: false,
 7236                type_tag: Some(type_id),
 7237            };
 7238            let creases = new_newlines
 7239                .into_iter()
 7240                .map(|range| Crease::simple(range, placeholder.clone()))
 7241                .collect();
 7242            this.update(cx, |this, cx| {
 7243                this.display_map.update(cx, |display_map, cx| {
 7244                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7245                    display_map.fold(creases, cx);
 7246                });
 7247            })
 7248            .ok();
 7249        });
 7250    }
 7251
 7252    #[ztracing::instrument(skip_all)]
 7253    fn refresh_selected_text_highlights(
 7254        &mut self,
 7255        on_buffer_edit: bool,
 7256        window: &mut Window,
 7257        cx: &mut Context<Editor>,
 7258    ) {
 7259        let Some((query_text, query_range)) =
 7260            self.prepare_highlight_query_from_selection(window, cx)
 7261        else {
 7262            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7263            self.quick_selection_highlight_task.take();
 7264            self.debounced_selection_highlight_task.take();
 7265            return;
 7266        };
 7267        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7268        if on_buffer_edit
 7269            || self
 7270                .quick_selection_highlight_task
 7271                .as_ref()
 7272                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7273        {
 7274            let multi_buffer_visible_start = self
 7275                .scroll_manager
 7276                .anchor()
 7277                .anchor
 7278                .to_point(&multi_buffer_snapshot);
 7279            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7280                multi_buffer_visible_start
 7281                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7282                Bias::Left,
 7283            );
 7284            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7285            self.quick_selection_highlight_task = Some((
 7286                query_range.clone(),
 7287                self.update_selection_occurrence_highlights(
 7288                    query_text.clone(),
 7289                    query_range.clone(),
 7290                    multi_buffer_visible_range,
 7291                    false,
 7292                    window,
 7293                    cx,
 7294                ),
 7295            ));
 7296        }
 7297        if on_buffer_edit
 7298            || self
 7299                .debounced_selection_highlight_task
 7300                .as_ref()
 7301                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7302        {
 7303            let multi_buffer_start = multi_buffer_snapshot
 7304                .anchor_before(MultiBufferOffset(0))
 7305                .to_point(&multi_buffer_snapshot);
 7306            let multi_buffer_end = multi_buffer_snapshot
 7307                .anchor_after(multi_buffer_snapshot.len())
 7308                .to_point(&multi_buffer_snapshot);
 7309            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7310            self.debounced_selection_highlight_task = Some((
 7311                query_range.clone(),
 7312                self.update_selection_occurrence_highlights(
 7313                    query_text,
 7314                    query_range,
 7315                    multi_buffer_full_range,
 7316                    true,
 7317                    window,
 7318                    cx,
 7319                ),
 7320            ));
 7321        }
 7322    }
 7323
 7324    pub fn refresh_edit_prediction(
 7325        &mut self,
 7326        debounce: bool,
 7327        user_requested: bool,
 7328        window: &mut Window,
 7329        cx: &mut Context<Self>,
 7330    ) -> Option<()> {
 7331        if DisableAiSettings::get_global(cx).disable_ai {
 7332            return None;
 7333        }
 7334
 7335        let provider = self.edit_prediction_provider()?;
 7336        let cursor = self.selections.newest_anchor().head();
 7337        let (buffer, cursor_buffer_position) =
 7338            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7339
 7340        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7341            self.discard_edit_prediction(false, cx);
 7342            return None;
 7343        }
 7344
 7345        self.update_visible_edit_prediction(window, cx);
 7346
 7347        if !user_requested
 7348            && (!self.should_show_edit_predictions()
 7349                || !self.is_focused(window)
 7350                || buffer.read(cx).is_empty())
 7351        {
 7352            self.discard_edit_prediction(false, cx);
 7353            return None;
 7354        }
 7355
 7356        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7357        Some(())
 7358    }
 7359
 7360    fn show_edit_predictions_in_menu(&self) -> bool {
 7361        match self.edit_prediction_settings {
 7362            EditPredictionSettings::Disabled => false,
 7363            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7364        }
 7365    }
 7366
 7367    pub fn edit_predictions_enabled(&self) -> bool {
 7368        match self.edit_prediction_settings {
 7369            EditPredictionSettings::Disabled => false,
 7370            EditPredictionSettings::Enabled { .. } => true,
 7371        }
 7372    }
 7373
 7374    fn edit_prediction_requires_modifier(&self) -> bool {
 7375        match self.edit_prediction_settings {
 7376            EditPredictionSettings::Disabled => false,
 7377            EditPredictionSettings::Enabled {
 7378                preview_requires_modifier,
 7379                ..
 7380            } => preview_requires_modifier,
 7381        }
 7382    }
 7383
 7384    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7385        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7386            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7387            self.discard_edit_prediction(false, cx);
 7388        } else {
 7389            let selection = self.selections.newest_anchor();
 7390            let cursor = selection.head();
 7391
 7392            if let Some((buffer, cursor_buffer_position)) =
 7393                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7394            {
 7395                self.edit_prediction_settings =
 7396                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7397            }
 7398        }
 7399    }
 7400
 7401    fn edit_prediction_settings_at_position(
 7402        &self,
 7403        buffer: &Entity<Buffer>,
 7404        buffer_position: language::Anchor,
 7405        cx: &App,
 7406    ) -> EditPredictionSettings {
 7407        if !self.mode.is_full()
 7408            || !self.show_edit_predictions_override.unwrap_or(true)
 7409            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7410        {
 7411            return EditPredictionSettings::Disabled;
 7412        }
 7413
 7414        let buffer = buffer.read(cx);
 7415
 7416        let file = buffer.file();
 7417
 7418        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7419            return EditPredictionSettings::Disabled;
 7420        };
 7421
 7422        let by_provider = matches!(
 7423            self.menu_edit_predictions_policy,
 7424            MenuEditPredictionsPolicy::ByProvider
 7425        );
 7426
 7427        let show_in_menu = by_provider
 7428            && self
 7429                .edit_prediction_provider
 7430                .as_ref()
 7431                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7432
 7433        let preview_requires_modifier =
 7434            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7435
 7436        EditPredictionSettings::Enabled {
 7437            show_in_menu,
 7438            preview_requires_modifier,
 7439        }
 7440    }
 7441
 7442    fn should_show_edit_predictions(&self) -> bool {
 7443        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7444    }
 7445
 7446    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7447        matches!(
 7448            self.edit_prediction_preview,
 7449            EditPredictionPreview::Active { .. }
 7450        )
 7451    }
 7452
 7453    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7454        let cursor = self.selections.newest_anchor().head();
 7455        if let Some((buffer, cursor_position)) =
 7456            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7457        {
 7458            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7459        } else {
 7460            false
 7461        }
 7462    }
 7463
 7464    pub fn supports_minimap(&self, cx: &App) -> bool {
 7465        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7466    }
 7467
 7468    fn edit_predictions_enabled_in_buffer(
 7469        &self,
 7470        buffer: &Entity<Buffer>,
 7471        buffer_position: language::Anchor,
 7472        cx: &App,
 7473    ) -> bool {
 7474        maybe!({
 7475            if self.read_only(cx) {
 7476                return Some(false);
 7477            }
 7478            let provider = self.edit_prediction_provider()?;
 7479            if !provider.is_enabled(buffer, buffer_position, cx) {
 7480                return Some(false);
 7481            }
 7482            let buffer = buffer.read(cx);
 7483            let Some(file) = buffer.file() else {
 7484                return Some(true);
 7485            };
 7486            let settings = all_language_settings(Some(file), cx);
 7487            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7488        })
 7489        .unwrap_or(false)
 7490    }
 7491
 7492    pub fn show_edit_prediction(
 7493        &mut self,
 7494        _: &ShowEditPrediction,
 7495        window: &mut Window,
 7496        cx: &mut Context<Self>,
 7497    ) {
 7498        if !self.has_active_edit_prediction() {
 7499            self.refresh_edit_prediction(false, true, window, cx);
 7500            return;
 7501        }
 7502
 7503        self.update_visible_edit_prediction(window, cx);
 7504    }
 7505
 7506    pub fn display_cursor_names(
 7507        &mut self,
 7508        _: &DisplayCursorNames,
 7509        window: &mut Window,
 7510        cx: &mut Context<Self>,
 7511    ) {
 7512        self.show_cursor_names(window, cx);
 7513    }
 7514
 7515    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7516        self.show_cursor_names = true;
 7517        cx.notify();
 7518        cx.spawn_in(window, async move |this, cx| {
 7519            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7520            this.update(cx, |this, cx| {
 7521                this.show_cursor_names = false;
 7522                cx.notify()
 7523            })
 7524            .ok()
 7525        })
 7526        .detach();
 7527    }
 7528
 7529    pub fn accept_partial_edit_prediction(
 7530        &mut self,
 7531        granularity: EditPredictionGranularity,
 7532        window: &mut Window,
 7533        cx: &mut Context<Self>,
 7534    ) {
 7535        if self.show_edit_predictions_in_menu() {
 7536            self.hide_context_menu(window, cx);
 7537        }
 7538
 7539        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7540            return;
 7541        };
 7542
 7543        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7544            return;
 7545        }
 7546
 7547        match &active_edit_prediction.completion {
 7548            EditPrediction::MoveWithin { target, .. } => {
 7549                let target = *target;
 7550
 7551                if matches!(granularity, EditPredictionGranularity::Full) {
 7552                    if let Some(position_map) = &self.last_position_map {
 7553                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7554                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7555
 7556                        if is_visible || !self.edit_prediction_requires_modifier() {
 7557                            self.unfold_ranges(&[target..target], true, false, cx);
 7558                            self.change_selections(
 7559                                SelectionEffects::scroll(Autoscroll::newest()),
 7560                                window,
 7561                                cx,
 7562                                |selections| {
 7563                                    selections.select_anchor_ranges([target..target]);
 7564                                },
 7565                            );
 7566                            self.clear_row_highlights::<EditPredictionPreview>();
 7567                            self.edit_prediction_preview
 7568                                .set_previous_scroll_position(None);
 7569                        } else {
 7570                            // Highlight and request scroll
 7571                            self.edit_prediction_preview
 7572                                .set_previous_scroll_position(Some(
 7573                                    position_map.snapshot.scroll_anchor,
 7574                                ));
 7575                            self.highlight_rows::<EditPredictionPreview>(
 7576                                target..target,
 7577                                cx.theme().colors().editor_highlighted_line_background,
 7578                                RowHighlightOptions {
 7579                                    autoscroll: true,
 7580                                    ..Default::default()
 7581                                },
 7582                                cx,
 7583                            );
 7584                            self.request_autoscroll(Autoscroll::fit(), cx);
 7585                        }
 7586                    }
 7587                } else {
 7588                    self.change_selections(
 7589                        SelectionEffects::scroll(Autoscroll::newest()),
 7590                        window,
 7591                        cx,
 7592                        |selections| {
 7593                            selections.select_anchor_ranges([target..target]);
 7594                        },
 7595                    );
 7596                }
 7597            }
 7598            EditPrediction::MoveOutside { snapshot, target } => {
 7599                if let Some(workspace) = self.workspace() {
 7600                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7601                        .detach_and_log_err(cx);
 7602                }
 7603            }
 7604            EditPrediction::Edit { edits, .. } => {
 7605                self.report_edit_prediction_event(
 7606                    active_edit_prediction.completion_id.clone(),
 7607                    true,
 7608                    cx,
 7609                );
 7610
 7611                match granularity {
 7612                    EditPredictionGranularity::Full => {
 7613                        if let Some(provider) = self.edit_prediction_provider() {
 7614                            provider.accept(cx);
 7615                        }
 7616
 7617                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7618                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7619                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7620
 7621                        self.buffer.update(cx, |buffer, cx| {
 7622                            buffer.edit(edits.iter().cloned(), None, cx)
 7623                        });
 7624
 7625                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7626                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7627                        });
 7628
 7629                        let selections = self.selections.disjoint_anchors_arc();
 7630                        if let Some(transaction_id_now) =
 7631                            self.buffer.read(cx).last_transaction_id(cx)
 7632                        {
 7633                            if transaction_id_prev != Some(transaction_id_now) {
 7634                                self.selection_history
 7635                                    .insert_transaction(transaction_id_now, selections);
 7636                            }
 7637                        }
 7638
 7639                        self.update_visible_edit_prediction(window, cx);
 7640                        if self.active_edit_prediction.is_none() {
 7641                            self.refresh_edit_prediction(true, true, window, cx);
 7642                        }
 7643                        cx.notify();
 7644                    }
 7645                    _ => {
 7646                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7647                        let cursor_offset = self
 7648                            .selections
 7649                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7650                            .head();
 7651
 7652                        let insertion = edits.iter().find_map(|(range, text)| {
 7653                            let range = range.to_offset(&snapshot);
 7654                            if range.is_empty() && range.start == cursor_offset {
 7655                                Some(text)
 7656                            } else {
 7657                                None
 7658                            }
 7659                        });
 7660
 7661                        if let Some(text) = insertion {
 7662                            let text_to_insert = match granularity {
 7663                                EditPredictionGranularity::Word => {
 7664                                    let mut partial = text
 7665                                        .chars()
 7666                                        .by_ref()
 7667                                        .take_while(|c| c.is_alphabetic())
 7668                                        .collect::<String>();
 7669                                    if partial.is_empty() {
 7670                                        partial = text
 7671                                            .chars()
 7672                                            .by_ref()
 7673                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7674                                            .collect::<String>();
 7675                                    }
 7676                                    partial
 7677                                }
 7678                                EditPredictionGranularity::Line => {
 7679                                    if let Some(line) = text.split_inclusive('\n').next() {
 7680                                        line.to_string()
 7681                                    } else {
 7682                                        text.to_string()
 7683                                    }
 7684                                }
 7685                                EditPredictionGranularity::Full => unreachable!(),
 7686                            };
 7687
 7688                            cx.emit(EditorEvent::InputHandled {
 7689                                utf16_range_to_replace: None,
 7690                                text: text_to_insert.clone().into(),
 7691                            });
 7692
 7693                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7694                            self.refresh_edit_prediction(true, true, window, cx);
 7695                            cx.notify();
 7696                        } else {
 7697                            self.accept_partial_edit_prediction(
 7698                                EditPredictionGranularity::Full,
 7699                                window,
 7700                                cx,
 7701                            );
 7702                        }
 7703                    }
 7704                }
 7705            }
 7706        }
 7707
 7708        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7709    }
 7710
 7711    pub fn accept_next_word_edit_prediction(
 7712        &mut self,
 7713        _: &AcceptNextWordEditPrediction,
 7714        window: &mut Window,
 7715        cx: &mut Context<Self>,
 7716    ) {
 7717        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7718    }
 7719
 7720    pub fn accept_next_line_edit_prediction(
 7721        &mut self,
 7722        _: &AcceptNextLineEditPrediction,
 7723        window: &mut Window,
 7724        cx: &mut Context<Self>,
 7725    ) {
 7726        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7727    }
 7728
 7729    pub fn accept_edit_prediction(
 7730        &mut self,
 7731        _: &AcceptEditPrediction,
 7732        window: &mut Window,
 7733        cx: &mut Context<Self>,
 7734    ) {
 7735        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7736    }
 7737
 7738    fn discard_edit_prediction(
 7739        &mut self,
 7740        should_report_edit_prediction_event: bool,
 7741        cx: &mut Context<Self>,
 7742    ) -> bool {
 7743        if should_report_edit_prediction_event {
 7744            let completion_id = self
 7745                .active_edit_prediction
 7746                .as_ref()
 7747                .and_then(|active_completion| active_completion.completion_id.clone());
 7748
 7749            self.report_edit_prediction_event(completion_id, false, cx);
 7750        }
 7751
 7752        if let Some(provider) = self.edit_prediction_provider() {
 7753            provider.discard(cx);
 7754        }
 7755
 7756        self.take_active_edit_prediction(cx)
 7757    }
 7758
 7759    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7760        let Some(provider) = self.edit_prediction_provider() else {
 7761            return;
 7762        };
 7763
 7764        let Some((_, buffer, _)) = self
 7765            .buffer
 7766            .read(cx)
 7767            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7768        else {
 7769            return;
 7770        };
 7771
 7772        let extension = buffer
 7773            .read(cx)
 7774            .file()
 7775            .and_then(|file| Some(file.path().extension()?.to_string()));
 7776
 7777        let event_type = match accepted {
 7778            true => "Edit Prediction Accepted",
 7779            false => "Edit Prediction Discarded",
 7780        };
 7781        telemetry::event!(
 7782            event_type,
 7783            provider = provider.name(),
 7784            prediction_id = id,
 7785            suggestion_accepted = accepted,
 7786            file_extension = extension,
 7787        );
 7788    }
 7789
 7790    fn open_editor_at_anchor(
 7791        snapshot: &language::BufferSnapshot,
 7792        target: language::Anchor,
 7793        workspace: &Entity<Workspace>,
 7794        window: &mut Window,
 7795        cx: &mut App,
 7796    ) -> Task<Result<()>> {
 7797        workspace.update(cx, |workspace, cx| {
 7798            let path = snapshot.file().map(|file| file.full_path(cx));
 7799            let Some(path) =
 7800                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7801            else {
 7802                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7803            };
 7804            let target = text::ToPoint::to_point(&target, snapshot);
 7805            let item = workspace.open_path(path, None, true, window, cx);
 7806            window.spawn(cx, async move |cx| {
 7807                let Some(editor) = item.await?.downcast::<Editor>() else {
 7808                    return Ok(());
 7809                };
 7810                editor
 7811                    .update_in(cx, |editor, window, cx| {
 7812                        editor.go_to_singleton_buffer_point(target, window, cx);
 7813                    })
 7814                    .ok();
 7815                anyhow::Ok(())
 7816            })
 7817        })
 7818    }
 7819
 7820    pub fn has_active_edit_prediction(&self) -> bool {
 7821        self.active_edit_prediction.is_some()
 7822    }
 7823
 7824    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7825        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7826            return false;
 7827        };
 7828
 7829        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7830        self.clear_highlights::<EditPredictionHighlight>(cx);
 7831        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7832        true
 7833    }
 7834
 7835    /// Returns true when we're displaying the edit prediction popover below the cursor
 7836    /// like we are not previewing and the LSP autocomplete menu is visible
 7837    /// or we are in `when_holding_modifier` mode.
 7838    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7839        if self.edit_prediction_preview_is_active()
 7840            || !self.show_edit_predictions_in_menu()
 7841            || !self.edit_predictions_enabled()
 7842        {
 7843            return false;
 7844        }
 7845
 7846        if self.has_visible_completions_menu() {
 7847            return true;
 7848        }
 7849
 7850        has_completion && self.edit_prediction_requires_modifier()
 7851    }
 7852
 7853    fn handle_modifiers_changed(
 7854        &mut self,
 7855        modifiers: Modifiers,
 7856        position_map: &PositionMap,
 7857        window: &mut Window,
 7858        cx: &mut Context<Self>,
 7859    ) {
 7860        // Ensure that the edit prediction preview is updated, even when not
 7861        // enabled, if there's an active edit prediction preview.
 7862        if self.show_edit_predictions_in_menu()
 7863            || matches!(
 7864                self.edit_prediction_preview,
 7865                EditPredictionPreview::Active { .. }
 7866            )
 7867        {
 7868            self.update_edit_prediction_preview(&modifiers, window, cx);
 7869        }
 7870
 7871        self.update_selection_mode(&modifiers, position_map, window, cx);
 7872
 7873        let mouse_position = window.mouse_position();
 7874        if !position_map.text_hitbox.is_hovered(window) {
 7875            return;
 7876        }
 7877
 7878        self.update_hovered_link(
 7879            position_map.point_for_position(mouse_position),
 7880            &position_map.snapshot,
 7881            modifiers,
 7882            window,
 7883            cx,
 7884        )
 7885    }
 7886
 7887    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7888        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7889            MultiCursorModifier::Alt => modifiers.secondary(),
 7890            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7891        }
 7892    }
 7893
 7894    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7895        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7896            MultiCursorModifier::Alt => modifiers.alt,
 7897            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7898        }
 7899    }
 7900
 7901    fn columnar_selection_mode(
 7902        modifiers: &Modifiers,
 7903        cx: &mut Context<Self>,
 7904    ) -> Option<ColumnarMode> {
 7905        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7906            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7907                Some(ColumnarMode::FromMouse)
 7908            } else if Self::is_alt_pressed(modifiers, cx) {
 7909                Some(ColumnarMode::FromSelection)
 7910            } else {
 7911                None
 7912            }
 7913        } else {
 7914            None
 7915        }
 7916    }
 7917
 7918    fn update_selection_mode(
 7919        &mut self,
 7920        modifiers: &Modifiers,
 7921        position_map: &PositionMap,
 7922        window: &mut Window,
 7923        cx: &mut Context<Self>,
 7924    ) {
 7925        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7926            return;
 7927        };
 7928        if self.selections.pending_anchor().is_none() {
 7929            return;
 7930        }
 7931
 7932        let mouse_position = window.mouse_position();
 7933        let point_for_position = position_map.point_for_position(mouse_position);
 7934        let position = point_for_position.previous_valid;
 7935
 7936        self.select(
 7937            SelectPhase::BeginColumnar {
 7938                position,
 7939                reset: false,
 7940                mode,
 7941                goal_column: point_for_position.exact_unclipped.column(),
 7942            },
 7943            window,
 7944            cx,
 7945        );
 7946    }
 7947
 7948    fn update_edit_prediction_preview(
 7949        &mut self,
 7950        modifiers: &Modifiers,
 7951        window: &mut Window,
 7952        cx: &mut Context<Self>,
 7953    ) {
 7954        let mut modifiers_held = false;
 7955
 7956        // Check bindings for all granularities.
 7957        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 7958        let granularities = [
 7959            EditPredictionGranularity::Full,
 7960            EditPredictionGranularity::Line,
 7961            EditPredictionGranularity::Word,
 7962        ];
 7963
 7964        for granularity in granularities {
 7965            if let Some(keystroke) = self
 7966                .accept_edit_prediction_keybind(granularity, window, cx)
 7967                .keystroke()
 7968            {
 7969                modifiers_held = modifiers_held
 7970                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 7971            }
 7972        }
 7973
 7974        if modifiers_held {
 7975            if matches!(
 7976                self.edit_prediction_preview,
 7977                EditPredictionPreview::Inactive { .. }
 7978            ) {
 7979                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7980                    provider.provider.did_show(cx)
 7981                }
 7982
 7983                self.edit_prediction_preview = EditPredictionPreview::Active {
 7984                    previous_scroll_position: None,
 7985                    since: Instant::now(),
 7986                };
 7987
 7988                self.update_visible_edit_prediction(window, cx);
 7989                cx.notify();
 7990            }
 7991        } else if let EditPredictionPreview::Active {
 7992            previous_scroll_position,
 7993            since,
 7994        } = self.edit_prediction_preview
 7995        {
 7996            if let (Some(previous_scroll_position), Some(position_map)) =
 7997                (previous_scroll_position, self.last_position_map.as_ref())
 7998            {
 7999                self.set_scroll_position(
 8000                    previous_scroll_position
 8001                        .scroll_position(&position_map.snapshot.display_snapshot),
 8002                    window,
 8003                    cx,
 8004                );
 8005            }
 8006
 8007            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8008                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8009            };
 8010            self.clear_row_highlights::<EditPredictionPreview>();
 8011            self.update_visible_edit_prediction(window, cx);
 8012            cx.notify();
 8013        }
 8014    }
 8015
 8016    fn update_visible_edit_prediction(
 8017        &mut self,
 8018        _window: &mut Window,
 8019        cx: &mut Context<Self>,
 8020    ) -> Option<()> {
 8021        if DisableAiSettings::get_global(cx).disable_ai {
 8022            return None;
 8023        }
 8024
 8025        if self.ime_transaction.is_some() {
 8026            self.discard_edit_prediction(false, cx);
 8027            return None;
 8028        }
 8029
 8030        let selection = self.selections.newest_anchor();
 8031        let cursor = selection.head();
 8032        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8033        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8034        let excerpt_id = cursor.excerpt_id;
 8035
 8036        let show_in_menu = self.show_edit_predictions_in_menu();
 8037        let completions_menu_has_precedence = !show_in_menu
 8038            && (self.context_menu.borrow().is_some()
 8039                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8040
 8041        if completions_menu_has_precedence
 8042            || !offset_selection.is_empty()
 8043            || self
 8044                .active_edit_prediction
 8045                .as_ref()
 8046                .is_some_and(|completion| {
 8047                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8048                        return false;
 8049                    };
 8050                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8051                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8052                    !invalidation_range.contains(&offset_selection.head())
 8053                })
 8054        {
 8055            self.discard_edit_prediction(false, cx);
 8056            return None;
 8057        }
 8058
 8059        self.take_active_edit_prediction(cx);
 8060        let Some(provider) = self.edit_prediction_provider() else {
 8061            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8062            return None;
 8063        };
 8064
 8065        let (buffer, cursor_buffer_position) =
 8066            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8067
 8068        self.edit_prediction_settings =
 8069            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8070
 8071        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8072
 8073        if self.edit_prediction_indent_conflict {
 8074            let cursor_point = cursor.to_point(&multibuffer);
 8075            let mut suggested_indent = None;
 8076            multibuffer.suggested_indents_callback(
 8077                cursor_point.row..cursor_point.row + 1,
 8078                |_, indent| {
 8079                    suggested_indent = Some(indent);
 8080                    ControlFlow::Break(())
 8081                },
 8082                cx,
 8083            );
 8084
 8085            if let Some(indent) = suggested_indent
 8086                && indent.len == cursor_point.column
 8087            {
 8088                self.edit_prediction_indent_conflict = false;
 8089            }
 8090        }
 8091
 8092        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8093
 8094        let (completion_id, edits, edit_preview) = match edit_prediction {
 8095            edit_prediction_types::EditPrediction::Local {
 8096                id,
 8097                edits,
 8098                edit_preview,
 8099            } => (id, edits, edit_preview),
 8100            edit_prediction_types::EditPrediction::Jump {
 8101                id,
 8102                snapshot,
 8103                target,
 8104            } => {
 8105                self.stale_edit_prediction_in_menu = None;
 8106                self.active_edit_prediction = Some(EditPredictionState {
 8107                    inlay_ids: vec![],
 8108                    completion: EditPrediction::MoveOutside { snapshot, target },
 8109                    completion_id: id,
 8110                    invalidation_range: None,
 8111                });
 8112                cx.notify();
 8113                return Some(());
 8114            }
 8115        };
 8116
 8117        let edits = edits
 8118            .into_iter()
 8119            .flat_map(|(range, new_text)| {
 8120                Some((
 8121                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8122                    new_text,
 8123                ))
 8124            })
 8125            .collect::<Vec<_>>();
 8126        if edits.is_empty() {
 8127            return None;
 8128        }
 8129
 8130        let first_edit_start = edits.first().unwrap().0.start;
 8131        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8132        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8133
 8134        let last_edit_end = edits.last().unwrap().0.end;
 8135        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8136        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8137
 8138        let cursor_row = cursor.to_point(&multibuffer).row;
 8139
 8140        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8141
 8142        let mut inlay_ids = Vec::new();
 8143        let invalidation_row_range;
 8144        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8145            Some(cursor_row..edit_end_row)
 8146        } else if cursor_row > edit_end_row {
 8147            Some(edit_start_row..cursor_row)
 8148        } else {
 8149            None
 8150        };
 8151        let supports_jump = self
 8152            .edit_prediction_provider
 8153            .as_ref()
 8154            .map(|provider| provider.provider.supports_jump_to_edit())
 8155            .unwrap_or(true);
 8156
 8157        let is_move = supports_jump
 8158            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8159        let completion = if is_move {
 8160            invalidation_row_range =
 8161                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8162            let target = first_edit_start;
 8163            EditPrediction::MoveWithin { target, snapshot }
 8164        } else {
 8165            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8166                && !self.edit_predictions_hidden_for_vim_mode;
 8167
 8168            if show_completions_in_buffer {
 8169                if let Some(provider) = &self.edit_prediction_provider {
 8170                    provider.provider.did_show(cx);
 8171                }
 8172                if edits
 8173                    .iter()
 8174                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8175                {
 8176                    let mut inlays = Vec::new();
 8177                    for (range, new_text) in &edits {
 8178                        let inlay = Inlay::edit_prediction(
 8179                            post_inc(&mut self.next_inlay_id),
 8180                            range.start,
 8181                            new_text.as_ref(),
 8182                        );
 8183                        inlay_ids.push(inlay.id);
 8184                        inlays.push(inlay);
 8185                    }
 8186
 8187                    self.splice_inlays(&[], inlays, cx);
 8188                } else {
 8189                    let background_color = cx.theme().status().deleted_background;
 8190                    self.highlight_text::<EditPredictionHighlight>(
 8191                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8192                        HighlightStyle {
 8193                            background_color: Some(background_color),
 8194                            ..Default::default()
 8195                        },
 8196                        cx,
 8197                    );
 8198                }
 8199            }
 8200
 8201            invalidation_row_range = edit_start_row..edit_end_row;
 8202
 8203            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8204                if provider.show_tab_accept_marker() {
 8205                    EditDisplayMode::TabAccept
 8206                } else {
 8207                    EditDisplayMode::Inline
 8208                }
 8209            } else {
 8210                EditDisplayMode::DiffPopover
 8211            };
 8212
 8213            EditPrediction::Edit {
 8214                edits,
 8215                edit_preview,
 8216                display_mode,
 8217                snapshot,
 8218            }
 8219        };
 8220
 8221        let invalidation_range = multibuffer
 8222            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8223            ..multibuffer.anchor_after(Point::new(
 8224                invalidation_row_range.end,
 8225                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8226            ));
 8227
 8228        self.stale_edit_prediction_in_menu = None;
 8229        self.active_edit_prediction = Some(EditPredictionState {
 8230            inlay_ids,
 8231            completion,
 8232            completion_id,
 8233            invalidation_range: Some(invalidation_range),
 8234        });
 8235
 8236        cx.notify();
 8237
 8238        Some(())
 8239    }
 8240
 8241    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8242        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8243    }
 8244
 8245    fn clear_tasks(&mut self) {
 8246        self.tasks.clear()
 8247    }
 8248
 8249    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8250        if self.tasks.insert(key, value).is_some() {
 8251            // This case should hopefully be rare, but just in case...
 8252            log::error!(
 8253                "multiple different run targets found on a single line, only the last target will be rendered"
 8254            )
 8255        }
 8256    }
 8257
 8258    /// Get all display points of breakpoints that will be rendered within editor
 8259    ///
 8260    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8261    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8262    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8263    fn active_breakpoints(
 8264        &self,
 8265        range: Range<DisplayRow>,
 8266        window: &mut Window,
 8267        cx: &mut Context<Self>,
 8268    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8269        let mut breakpoint_display_points = HashMap::default();
 8270
 8271        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8272            return breakpoint_display_points;
 8273        };
 8274
 8275        let snapshot = self.snapshot(window, cx);
 8276
 8277        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8278        let Some(project) = self.project() else {
 8279            return breakpoint_display_points;
 8280        };
 8281
 8282        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8283            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8284
 8285        for (buffer_snapshot, range, excerpt_id) in
 8286            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8287        {
 8288            let Some(buffer) = project
 8289                .read(cx)
 8290                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8291            else {
 8292                continue;
 8293            };
 8294            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8295                &buffer,
 8296                Some(
 8297                    buffer_snapshot.anchor_before(range.start)
 8298                        ..buffer_snapshot.anchor_after(range.end),
 8299                ),
 8300                buffer_snapshot,
 8301                cx,
 8302            );
 8303            for (breakpoint, state) in breakpoints {
 8304                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8305                let position = multi_buffer_anchor
 8306                    .to_point(&multi_buffer_snapshot)
 8307                    .to_display_point(&snapshot);
 8308
 8309                breakpoint_display_points.insert(
 8310                    position.row(),
 8311                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8312                );
 8313            }
 8314        }
 8315
 8316        breakpoint_display_points
 8317    }
 8318
 8319    fn breakpoint_context_menu(
 8320        &self,
 8321        anchor: Anchor,
 8322        window: &mut Window,
 8323        cx: &mut Context<Self>,
 8324    ) -> Entity<ui::ContextMenu> {
 8325        let weak_editor = cx.weak_entity();
 8326        let focus_handle = self.focus_handle(cx);
 8327
 8328        let row = self
 8329            .buffer
 8330            .read(cx)
 8331            .snapshot(cx)
 8332            .summary_for_anchor::<Point>(&anchor)
 8333            .row;
 8334
 8335        let breakpoint = self
 8336            .breakpoint_at_row(row, window, cx)
 8337            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8338
 8339        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8340            "Edit Log Breakpoint"
 8341        } else {
 8342            "Set Log Breakpoint"
 8343        };
 8344
 8345        let condition_breakpoint_msg = if breakpoint
 8346            .as_ref()
 8347            .is_some_and(|bp| bp.1.condition.is_some())
 8348        {
 8349            "Edit Condition Breakpoint"
 8350        } else {
 8351            "Set Condition Breakpoint"
 8352        };
 8353
 8354        let hit_condition_breakpoint_msg = if breakpoint
 8355            .as_ref()
 8356            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8357        {
 8358            "Edit Hit Condition Breakpoint"
 8359        } else {
 8360            "Set Hit Condition Breakpoint"
 8361        };
 8362
 8363        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8364            "Unset Breakpoint"
 8365        } else {
 8366            "Set Breakpoint"
 8367        };
 8368
 8369        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8370
 8371        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8372            BreakpointState::Enabled => Some("Disable"),
 8373            BreakpointState::Disabled => Some("Enable"),
 8374        });
 8375
 8376        let (anchor, breakpoint) =
 8377            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8378
 8379        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8380            menu.on_blur_subscription(Subscription::new(|| {}))
 8381                .context(focus_handle)
 8382                .when(run_to_cursor, |this| {
 8383                    let weak_editor = weak_editor.clone();
 8384                    this.entry("Run to cursor", None, move |window, cx| {
 8385                        weak_editor
 8386                            .update(cx, |editor, cx| {
 8387                                editor.change_selections(
 8388                                    SelectionEffects::no_scroll(),
 8389                                    window,
 8390                                    cx,
 8391                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8392                                );
 8393                            })
 8394                            .ok();
 8395
 8396                        window.dispatch_action(Box::new(RunToCursor), cx);
 8397                    })
 8398                    .separator()
 8399                })
 8400                .when_some(toggle_state_msg, |this, msg| {
 8401                    this.entry(msg, None, {
 8402                        let weak_editor = weak_editor.clone();
 8403                        let breakpoint = breakpoint.clone();
 8404                        move |_window, cx| {
 8405                            weak_editor
 8406                                .update(cx, |this, cx| {
 8407                                    this.edit_breakpoint_at_anchor(
 8408                                        anchor,
 8409                                        breakpoint.as_ref().clone(),
 8410                                        BreakpointEditAction::InvertState,
 8411                                        cx,
 8412                                    );
 8413                                })
 8414                                .log_err();
 8415                        }
 8416                    })
 8417                })
 8418                .entry(set_breakpoint_msg, None, {
 8419                    let weak_editor = weak_editor.clone();
 8420                    let breakpoint = breakpoint.clone();
 8421                    move |_window, cx| {
 8422                        weak_editor
 8423                            .update(cx, |this, cx| {
 8424                                this.edit_breakpoint_at_anchor(
 8425                                    anchor,
 8426                                    breakpoint.as_ref().clone(),
 8427                                    BreakpointEditAction::Toggle,
 8428                                    cx,
 8429                                );
 8430                            })
 8431                            .log_err();
 8432                    }
 8433                })
 8434                .entry(log_breakpoint_msg, None, {
 8435                    let breakpoint = breakpoint.clone();
 8436                    let weak_editor = weak_editor.clone();
 8437                    move |window, cx| {
 8438                        weak_editor
 8439                            .update(cx, |this, cx| {
 8440                                this.add_edit_breakpoint_block(
 8441                                    anchor,
 8442                                    breakpoint.as_ref(),
 8443                                    BreakpointPromptEditAction::Log,
 8444                                    window,
 8445                                    cx,
 8446                                );
 8447                            })
 8448                            .log_err();
 8449                    }
 8450                })
 8451                .entry(condition_breakpoint_msg, None, {
 8452                    let breakpoint = breakpoint.clone();
 8453                    let weak_editor = weak_editor.clone();
 8454                    move |window, cx| {
 8455                        weak_editor
 8456                            .update(cx, |this, cx| {
 8457                                this.add_edit_breakpoint_block(
 8458                                    anchor,
 8459                                    breakpoint.as_ref(),
 8460                                    BreakpointPromptEditAction::Condition,
 8461                                    window,
 8462                                    cx,
 8463                                );
 8464                            })
 8465                            .log_err();
 8466                    }
 8467                })
 8468                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8469                    weak_editor
 8470                        .update(cx, |this, cx| {
 8471                            this.add_edit_breakpoint_block(
 8472                                anchor,
 8473                                breakpoint.as_ref(),
 8474                                BreakpointPromptEditAction::HitCondition,
 8475                                window,
 8476                                cx,
 8477                            );
 8478                        })
 8479                        .log_err();
 8480                })
 8481        })
 8482    }
 8483
 8484    fn render_breakpoint(
 8485        &self,
 8486        position: Anchor,
 8487        row: DisplayRow,
 8488        breakpoint: &Breakpoint,
 8489        state: Option<BreakpointSessionState>,
 8490        cx: &mut Context<Self>,
 8491    ) -> IconButton {
 8492        let is_rejected = state.is_some_and(|s| !s.verified);
 8493        // Is it a breakpoint that shows up when hovering over gutter?
 8494        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8495            (false, false),
 8496            |PhantomBreakpointIndicator {
 8497                 is_active,
 8498                 display_row,
 8499                 collides_with_existing_breakpoint,
 8500             }| {
 8501                (
 8502                    is_active && display_row == row,
 8503                    collides_with_existing_breakpoint,
 8504                )
 8505            },
 8506        );
 8507
 8508        let (color, icon) = {
 8509            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8510                (false, false) => ui::IconName::DebugBreakpoint,
 8511                (true, false) => ui::IconName::DebugLogBreakpoint,
 8512                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8513                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8514            };
 8515
 8516            let color = cx.theme().colors();
 8517
 8518            let color = if is_phantom {
 8519                if collides_with_existing {
 8520                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8521                } else {
 8522                    Color::Hint
 8523                }
 8524            } else if is_rejected {
 8525                Color::Disabled
 8526            } else {
 8527                Color::Debugger
 8528            };
 8529
 8530            (color, icon)
 8531        };
 8532
 8533        let breakpoint = Arc::from(breakpoint.clone());
 8534
 8535        let alt_as_text = gpui::Keystroke {
 8536            modifiers: Modifiers::secondary_key(),
 8537            ..Default::default()
 8538        };
 8539        let primary_action_text = if breakpoint.is_disabled() {
 8540            "Enable breakpoint"
 8541        } else if is_phantom && !collides_with_existing {
 8542            "Set breakpoint"
 8543        } else {
 8544            "Unset breakpoint"
 8545        };
 8546        let focus_handle = self.focus_handle.clone();
 8547
 8548        let meta = if is_rejected {
 8549            SharedString::from("No executable code is associated with this line.")
 8550        } else if collides_with_existing && !breakpoint.is_disabled() {
 8551            SharedString::from(format!(
 8552                "{alt_as_text}-click to disable,\nright-click for more options."
 8553            ))
 8554        } else {
 8555            SharedString::from("Right-click for more options.")
 8556        };
 8557        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8558            .icon_size(IconSize::XSmall)
 8559            .size(ui::ButtonSize::None)
 8560            .when(is_rejected, |this| {
 8561                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8562            })
 8563            .icon_color(color)
 8564            .style(ButtonStyle::Transparent)
 8565            .on_click(cx.listener({
 8566                move |editor, event: &ClickEvent, window, cx| {
 8567                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8568                        BreakpointEditAction::InvertState
 8569                    } else {
 8570                        BreakpointEditAction::Toggle
 8571                    };
 8572
 8573                    window.focus(&editor.focus_handle(cx), cx);
 8574                    editor.edit_breakpoint_at_anchor(
 8575                        position,
 8576                        breakpoint.as_ref().clone(),
 8577                        edit_action,
 8578                        cx,
 8579                    );
 8580                }
 8581            }))
 8582            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8583                editor.set_breakpoint_context_menu(
 8584                    row,
 8585                    Some(position),
 8586                    event.position(),
 8587                    window,
 8588                    cx,
 8589                );
 8590            }))
 8591            .tooltip(move |_window, cx| {
 8592                Tooltip::with_meta_in(
 8593                    primary_action_text,
 8594                    Some(&ToggleBreakpoint),
 8595                    meta.clone(),
 8596                    &focus_handle,
 8597                    cx,
 8598                )
 8599            })
 8600    }
 8601
 8602    fn build_tasks_context(
 8603        project: &Entity<Project>,
 8604        buffer: &Entity<Buffer>,
 8605        buffer_row: u32,
 8606        tasks: &Arc<RunnableTasks>,
 8607        cx: &mut Context<Self>,
 8608    ) -> Task<Option<task::TaskContext>> {
 8609        let position = Point::new(buffer_row, tasks.column);
 8610        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8611        let location = Location {
 8612            buffer: buffer.clone(),
 8613            range: range_start..range_start,
 8614        };
 8615        // Fill in the environmental variables from the tree-sitter captures
 8616        let mut captured_task_variables = TaskVariables::default();
 8617        for (capture_name, value) in tasks.extra_variables.clone() {
 8618            captured_task_variables.insert(
 8619                task::VariableName::Custom(capture_name.into()),
 8620                value.clone(),
 8621            );
 8622        }
 8623        project.update(cx, |project, cx| {
 8624            project.task_store().update(cx, |task_store, cx| {
 8625                task_store.task_context_for_location(captured_task_variables, location, cx)
 8626            })
 8627        })
 8628    }
 8629
 8630    pub fn spawn_nearest_task(
 8631        &mut self,
 8632        action: &SpawnNearestTask,
 8633        window: &mut Window,
 8634        cx: &mut Context<Self>,
 8635    ) {
 8636        let Some((workspace, _)) = self.workspace.clone() else {
 8637            return;
 8638        };
 8639        let Some(project) = self.project.clone() else {
 8640            return;
 8641        };
 8642
 8643        // Try to find a closest, enclosing node using tree-sitter that has a task
 8644        let Some((buffer, buffer_row, tasks)) = self
 8645            .find_enclosing_node_task(cx)
 8646            // Or find the task that's closest in row-distance.
 8647            .or_else(|| self.find_closest_task(cx))
 8648        else {
 8649            return;
 8650        };
 8651
 8652        let reveal_strategy = action.reveal;
 8653        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8654        cx.spawn_in(window, async move |_, cx| {
 8655            let context = task_context.await?;
 8656            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8657
 8658            let resolved = &mut resolved_task.resolved;
 8659            resolved.reveal = reveal_strategy;
 8660
 8661            workspace
 8662                .update_in(cx, |workspace, window, cx| {
 8663                    workspace.schedule_resolved_task(
 8664                        task_source_kind,
 8665                        resolved_task,
 8666                        false,
 8667                        window,
 8668                        cx,
 8669                    );
 8670                })
 8671                .ok()
 8672        })
 8673        .detach();
 8674    }
 8675
 8676    fn find_closest_task(
 8677        &mut self,
 8678        cx: &mut Context<Self>,
 8679    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8680        let cursor_row = self
 8681            .selections
 8682            .newest_adjusted(&self.display_snapshot(cx))
 8683            .head()
 8684            .row;
 8685
 8686        let ((buffer_id, row), tasks) = self
 8687            .tasks
 8688            .iter()
 8689            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8690
 8691        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8692        let tasks = Arc::new(tasks.to_owned());
 8693        Some((buffer, *row, tasks))
 8694    }
 8695
 8696    fn find_enclosing_node_task(
 8697        &mut self,
 8698        cx: &mut Context<Self>,
 8699    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8700        let snapshot = self.buffer.read(cx).snapshot(cx);
 8701        let offset = self
 8702            .selections
 8703            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8704            .head();
 8705        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8706        let offset = excerpt.map_offset_to_buffer(offset);
 8707        let buffer_id = excerpt.buffer().remote_id();
 8708
 8709        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8710        let mut cursor = layer.node().walk();
 8711
 8712        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8713            if cursor.node().end_byte() == offset.0 {
 8714                cursor.goto_next_sibling();
 8715            }
 8716        }
 8717
 8718        // Ascend to the smallest ancestor that contains the range and has a task.
 8719        loop {
 8720            let node = cursor.node();
 8721            let node_range = node.byte_range();
 8722            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8723
 8724            // Check if this node contains our offset
 8725            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8726                // If it contains offset, check for task
 8727                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8728                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8729                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8730                }
 8731            }
 8732
 8733            if !cursor.goto_parent() {
 8734                break;
 8735            }
 8736        }
 8737        None
 8738    }
 8739
 8740    fn render_run_indicator(
 8741        &self,
 8742        _style: &EditorStyle,
 8743        is_active: bool,
 8744        row: DisplayRow,
 8745        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8746        cx: &mut Context<Self>,
 8747    ) -> IconButton {
 8748        let color = Color::Muted;
 8749        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8750
 8751        IconButton::new(
 8752            ("run_indicator", row.0 as usize),
 8753            ui::IconName::PlayOutlined,
 8754        )
 8755        .shape(ui::IconButtonShape::Square)
 8756        .icon_size(IconSize::XSmall)
 8757        .icon_color(color)
 8758        .toggle_state(is_active)
 8759        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8760            let quick_launch = match e {
 8761                ClickEvent::Keyboard(_) => true,
 8762                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8763            };
 8764
 8765            window.focus(&editor.focus_handle(cx), cx);
 8766            editor.toggle_code_actions(
 8767                &ToggleCodeActions {
 8768                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8769                    quick_launch,
 8770                },
 8771                window,
 8772                cx,
 8773            );
 8774        }))
 8775        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8776            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8777        }))
 8778    }
 8779
 8780    pub fn context_menu_visible(&self) -> bool {
 8781        !self.edit_prediction_preview_is_active()
 8782            && self
 8783                .context_menu
 8784                .borrow()
 8785                .as_ref()
 8786                .is_some_and(|menu| menu.visible())
 8787    }
 8788
 8789    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8790        self.context_menu
 8791            .borrow()
 8792            .as_ref()
 8793            .map(|menu| menu.origin())
 8794    }
 8795
 8796    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8797        self.context_menu_options = Some(options);
 8798    }
 8799
 8800    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8801    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8802
 8803    fn render_edit_prediction_popover(
 8804        &mut self,
 8805        text_bounds: &Bounds<Pixels>,
 8806        content_origin: gpui::Point<Pixels>,
 8807        right_margin: Pixels,
 8808        editor_snapshot: &EditorSnapshot,
 8809        visible_row_range: Range<DisplayRow>,
 8810        scroll_top: ScrollOffset,
 8811        scroll_bottom: ScrollOffset,
 8812        line_layouts: &[LineWithInvisibles],
 8813        line_height: Pixels,
 8814        scroll_position: gpui::Point<ScrollOffset>,
 8815        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8816        newest_selection_head: Option<DisplayPoint>,
 8817        editor_width: Pixels,
 8818        style: &EditorStyle,
 8819        window: &mut Window,
 8820        cx: &mut App,
 8821    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8822        if self.mode().is_minimap() {
 8823            return None;
 8824        }
 8825        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8826
 8827        if self.edit_prediction_visible_in_cursor_popover(true) {
 8828            return None;
 8829        }
 8830
 8831        match &active_edit_prediction.completion {
 8832            EditPrediction::MoveWithin { target, .. } => {
 8833                let target_display_point = target.to_display_point(editor_snapshot);
 8834
 8835                if self.edit_prediction_requires_modifier() {
 8836                    if !self.edit_prediction_preview_is_active() {
 8837                        return None;
 8838                    }
 8839
 8840                    self.render_edit_prediction_modifier_jump_popover(
 8841                        text_bounds,
 8842                        content_origin,
 8843                        visible_row_range,
 8844                        line_layouts,
 8845                        line_height,
 8846                        scroll_pixel_position,
 8847                        newest_selection_head,
 8848                        target_display_point,
 8849                        window,
 8850                        cx,
 8851                    )
 8852                } else {
 8853                    self.render_edit_prediction_eager_jump_popover(
 8854                        text_bounds,
 8855                        content_origin,
 8856                        editor_snapshot,
 8857                        visible_row_range,
 8858                        scroll_top,
 8859                        scroll_bottom,
 8860                        line_height,
 8861                        scroll_pixel_position,
 8862                        target_display_point,
 8863                        editor_width,
 8864                        window,
 8865                        cx,
 8866                    )
 8867                }
 8868            }
 8869            EditPrediction::Edit {
 8870                display_mode: EditDisplayMode::Inline,
 8871                ..
 8872            } => None,
 8873            EditPrediction::Edit {
 8874                display_mode: EditDisplayMode::TabAccept,
 8875                edits,
 8876                ..
 8877            } => {
 8878                let range = &edits.first()?.0;
 8879                let target_display_point = range.end.to_display_point(editor_snapshot);
 8880
 8881                self.render_edit_prediction_end_of_line_popover(
 8882                    "Accept",
 8883                    editor_snapshot,
 8884                    visible_row_range,
 8885                    target_display_point,
 8886                    line_height,
 8887                    scroll_pixel_position,
 8888                    content_origin,
 8889                    editor_width,
 8890                    window,
 8891                    cx,
 8892                )
 8893            }
 8894            EditPrediction::Edit {
 8895                edits,
 8896                edit_preview,
 8897                display_mode: EditDisplayMode::DiffPopover,
 8898                snapshot,
 8899            } => self.render_edit_prediction_diff_popover(
 8900                text_bounds,
 8901                content_origin,
 8902                right_margin,
 8903                editor_snapshot,
 8904                visible_row_range,
 8905                line_layouts,
 8906                line_height,
 8907                scroll_position,
 8908                scroll_pixel_position,
 8909                newest_selection_head,
 8910                editor_width,
 8911                style,
 8912                edits,
 8913                edit_preview,
 8914                snapshot,
 8915                window,
 8916                cx,
 8917            ),
 8918            EditPrediction::MoveOutside { snapshot, .. } => {
 8919                let mut element = self
 8920                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8921                    .into_any();
 8922
 8923                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8924                let origin_x = text_bounds.size.width - size.width - px(30.);
 8925                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8926                element.prepaint_at(origin, window, cx);
 8927
 8928                Some((element, origin))
 8929            }
 8930        }
 8931    }
 8932
 8933    fn render_edit_prediction_modifier_jump_popover(
 8934        &mut self,
 8935        text_bounds: &Bounds<Pixels>,
 8936        content_origin: gpui::Point<Pixels>,
 8937        visible_row_range: Range<DisplayRow>,
 8938        line_layouts: &[LineWithInvisibles],
 8939        line_height: Pixels,
 8940        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8941        newest_selection_head: Option<DisplayPoint>,
 8942        target_display_point: DisplayPoint,
 8943        window: &mut Window,
 8944        cx: &mut App,
 8945    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8946        let scrolled_content_origin =
 8947            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8948
 8949        const SCROLL_PADDING_Y: Pixels = px(12.);
 8950
 8951        if target_display_point.row() < visible_row_range.start {
 8952            return self.render_edit_prediction_scroll_popover(
 8953                |_| SCROLL_PADDING_Y,
 8954                IconName::ArrowUp,
 8955                visible_row_range,
 8956                line_layouts,
 8957                newest_selection_head,
 8958                scrolled_content_origin,
 8959                window,
 8960                cx,
 8961            );
 8962        } else if target_display_point.row() >= visible_row_range.end {
 8963            return self.render_edit_prediction_scroll_popover(
 8964                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8965                IconName::ArrowDown,
 8966                visible_row_range,
 8967                line_layouts,
 8968                newest_selection_head,
 8969                scrolled_content_origin,
 8970                window,
 8971                cx,
 8972            );
 8973        }
 8974
 8975        const POLE_WIDTH: Pixels = px(2.);
 8976
 8977        let line_layout =
 8978            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8979        let target_column = target_display_point.column() as usize;
 8980
 8981        let target_x = line_layout.x_for_index(target_column);
 8982        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8983            - scroll_pixel_position.y;
 8984
 8985        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8986
 8987        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8988        border_color.l += 0.001;
 8989
 8990        let mut element = v_flex()
 8991            .items_end()
 8992            .when(flag_on_right, |el| el.items_start())
 8993            .child(if flag_on_right {
 8994                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8995                    .rounded_bl(px(0.))
 8996                    .rounded_tl(px(0.))
 8997                    .border_l_2()
 8998                    .border_color(border_color)
 8999            } else {
 9000                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9001                    .rounded_br(px(0.))
 9002                    .rounded_tr(px(0.))
 9003                    .border_r_2()
 9004                    .border_color(border_color)
 9005            })
 9006            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9007            .into_any();
 9008
 9009        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9010
 9011        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9012            - point(
 9013                if flag_on_right {
 9014                    POLE_WIDTH
 9015                } else {
 9016                    size.width - POLE_WIDTH
 9017                },
 9018                size.height - line_height,
 9019            );
 9020
 9021        origin.x = origin.x.max(content_origin.x);
 9022
 9023        element.prepaint_at(origin, window, cx);
 9024
 9025        Some((element, origin))
 9026    }
 9027
 9028    fn render_edit_prediction_scroll_popover(
 9029        &mut self,
 9030        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9031        scroll_icon: IconName,
 9032        visible_row_range: Range<DisplayRow>,
 9033        line_layouts: &[LineWithInvisibles],
 9034        newest_selection_head: Option<DisplayPoint>,
 9035        scrolled_content_origin: gpui::Point<Pixels>,
 9036        window: &mut Window,
 9037        cx: &mut App,
 9038    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9039        let mut element = self
 9040            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9041            .into_any();
 9042
 9043        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9044
 9045        let cursor = newest_selection_head?;
 9046        let cursor_row_layout =
 9047            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9048        let cursor_column = cursor.column() as usize;
 9049
 9050        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9051
 9052        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9053
 9054        element.prepaint_at(origin, window, cx);
 9055        Some((element, origin))
 9056    }
 9057
 9058    fn render_edit_prediction_eager_jump_popover(
 9059        &mut self,
 9060        text_bounds: &Bounds<Pixels>,
 9061        content_origin: gpui::Point<Pixels>,
 9062        editor_snapshot: &EditorSnapshot,
 9063        visible_row_range: Range<DisplayRow>,
 9064        scroll_top: ScrollOffset,
 9065        scroll_bottom: ScrollOffset,
 9066        line_height: Pixels,
 9067        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9068        target_display_point: DisplayPoint,
 9069        editor_width: Pixels,
 9070        window: &mut Window,
 9071        cx: &mut App,
 9072    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9073        if target_display_point.row().as_f64() < scroll_top {
 9074            let mut element = self
 9075                .render_edit_prediction_line_popover(
 9076                    "Jump to Edit",
 9077                    Some(IconName::ArrowUp),
 9078                    window,
 9079                    cx,
 9080                )
 9081                .into_any();
 9082
 9083            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9084            let offset = point(
 9085                (text_bounds.size.width - size.width) / 2.,
 9086                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9087            );
 9088
 9089            let origin = text_bounds.origin + offset;
 9090            element.prepaint_at(origin, window, cx);
 9091            Some((element, origin))
 9092        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9093            let mut element = self
 9094                .render_edit_prediction_line_popover(
 9095                    "Jump to Edit",
 9096                    Some(IconName::ArrowDown),
 9097                    window,
 9098                    cx,
 9099                )
 9100                .into_any();
 9101
 9102            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9103            let offset = point(
 9104                (text_bounds.size.width - size.width) / 2.,
 9105                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9106            );
 9107
 9108            let origin = text_bounds.origin + offset;
 9109            element.prepaint_at(origin, window, cx);
 9110            Some((element, origin))
 9111        } else {
 9112            self.render_edit_prediction_end_of_line_popover(
 9113                "Jump to Edit",
 9114                editor_snapshot,
 9115                visible_row_range,
 9116                target_display_point,
 9117                line_height,
 9118                scroll_pixel_position,
 9119                content_origin,
 9120                editor_width,
 9121                window,
 9122                cx,
 9123            )
 9124        }
 9125    }
 9126
 9127    fn render_edit_prediction_end_of_line_popover(
 9128        self: &mut Editor,
 9129        label: &'static str,
 9130        editor_snapshot: &EditorSnapshot,
 9131        visible_row_range: Range<DisplayRow>,
 9132        target_display_point: DisplayPoint,
 9133        line_height: Pixels,
 9134        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9135        content_origin: gpui::Point<Pixels>,
 9136        editor_width: Pixels,
 9137        window: &mut Window,
 9138        cx: &mut App,
 9139    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9140        let target_line_end = DisplayPoint::new(
 9141            target_display_point.row(),
 9142            editor_snapshot.line_len(target_display_point.row()),
 9143        );
 9144
 9145        let mut element = self
 9146            .render_edit_prediction_line_popover(label, None, window, cx)
 9147            .into_any();
 9148
 9149        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9150
 9151        let line_origin =
 9152            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9153
 9154        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9155        let mut origin = start_point
 9156            + line_origin
 9157            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9158        origin.x = origin.x.max(content_origin.x);
 9159
 9160        let max_x = content_origin.x + editor_width - size.width;
 9161
 9162        if origin.x > max_x {
 9163            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9164
 9165            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9166                origin.y += offset;
 9167                IconName::ArrowUp
 9168            } else {
 9169                origin.y -= offset;
 9170                IconName::ArrowDown
 9171            };
 9172
 9173            element = self
 9174                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9175                .into_any();
 9176
 9177            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9178
 9179            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9180        }
 9181
 9182        element.prepaint_at(origin, window, cx);
 9183        Some((element, origin))
 9184    }
 9185
 9186    fn render_edit_prediction_diff_popover(
 9187        self: &Editor,
 9188        text_bounds: &Bounds<Pixels>,
 9189        content_origin: gpui::Point<Pixels>,
 9190        right_margin: Pixels,
 9191        editor_snapshot: &EditorSnapshot,
 9192        visible_row_range: Range<DisplayRow>,
 9193        line_layouts: &[LineWithInvisibles],
 9194        line_height: Pixels,
 9195        scroll_position: gpui::Point<ScrollOffset>,
 9196        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9197        newest_selection_head: Option<DisplayPoint>,
 9198        editor_width: Pixels,
 9199        style: &EditorStyle,
 9200        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9201        edit_preview: &Option<language::EditPreview>,
 9202        snapshot: &language::BufferSnapshot,
 9203        window: &mut Window,
 9204        cx: &mut App,
 9205    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9206        let edit_start = edits
 9207            .first()
 9208            .unwrap()
 9209            .0
 9210            .start
 9211            .to_display_point(editor_snapshot);
 9212        let edit_end = edits
 9213            .last()
 9214            .unwrap()
 9215            .0
 9216            .end
 9217            .to_display_point(editor_snapshot);
 9218
 9219        let is_visible = visible_row_range.contains(&edit_start.row())
 9220            || visible_row_range.contains(&edit_end.row());
 9221        if !is_visible {
 9222            return None;
 9223        }
 9224
 9225        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9226            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9227        } else {
 9228            // Fallback for providers without edit_preview
 9229            crate::edit_prediction_fallback_text(edits, cx)
 9230        };
 9231
 9232        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9233        let line_count = highlighted_edits.text.lines().count();
 9234
 9235        const BORDER_WIDTH: Pixels = px(1.);
 9236
 9237        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9238        let has_keybind = keybind.is_some();
 9239
 9240        let mut element = h_flex()
 9241            .items_start()
 9242            .child(
 9243                h_flex()
 9244                    .bg(cx.theme().colors().editor_background)
 9245                    .border(BORDER_WIDTH)
 9246                    .shadow_xs()
 9247                    .border_color(cx.theme().colors().border)
 9248                    .rounded_l_lg()
 9249                    .when(line_count > 1, |el| el.rounded_br_lg())
 9250                    .pr_1()
 9251                    .child(styled_text),
 9252            )
 9253            .child(
 9254                h_flex()
 9255                    .h(line_height + BORDER_WIDTH * 2.)
 9256                    .px_1p5()
 9257                    .gap_1()
 9258                    // Workaround: For some reason, there's a gap if we don't do this
 9259                    .ml(-BORDER_WIDTH)
 9260                    .shadow(vec![gpui::BoxShadow {
 9261                        color: gpui::black().opacity(0.05),
 9262                        offset: point(px(1.), px(1.)),
 9263                        blur_radius: px(2.),
 9264                        spread_radius: px(0.),
 9265                    }])
 9266                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9267                    .border(BORDER_WIDTH)
 9268                    .border_color(cx.theme().colors().border)
 9269                    .rounded_r_lg()
 9270                    .id("edit_prediction_diff_popover_keybind")
 9271                    .when(!has_keybind, |el| {
 9272                        let status_colors = cx.theme().status();
 9273
 9274                        el.bg(status_colors.error_background)
 9275                            .border_color(status_colors.error.opacity(0.6))
 9276                            .child(Icon::new(IconName::Info).color(Color::Error))
 9277                            .cursor_default()
 9278                            .hoverable_tooltip(move |_window, cx| {
 9279                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9280                            })
 9281                    })
 9282                    .children(keybind),
 9283            )
 9284            .into_any();
 9285
 9286        let longest_row =
 9287            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9288        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9289            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9290        } else {
 9291            layout_line(
 9292                longest_row,
 9293                editor_snapshot,
 9294                style,
 9295                editor_width,
 9296                |_| false,
 9297                window,
 9298                cx,
 9299            )
 9300            .width
 9301        };
 9302
 9303        let viewport_bounds =
 9304            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9305                right: -right_margin,
 9306                ..Default::default()
 9307            });
 9308
 9309        let x_after_longest = Pixels::from(
 9310            ScrollPixelOffset::from(
 9311                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9312            ) - scroll_pixel_position.x,
 9313        );
 9314
 9315        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9316
 9317        // Fully visible if it can be displayed within the window (allow overlapping other
 9318        // panes). However, this is only allowed if the popover starts within text_bounds.
 9319        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9320            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9321
 9322        let mut origin = if can_position_to_the_right {
 9323            point(
 9324                x_after_longest,
 9325                text_bounds.origin.y
 9326                    + Pixels::from(
 9327                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9328                            - scroll_pixel_position.y,
 9329                    ),
 9330            )
 9331        } else {
 9332            let cursor_row = newest_selection_head.map(|head| head.row());
 9333            let above_edit = edit_start
 9334                .row()
 9335                .0
 9336                .checked_sub(line_count as u32)
 9337                .map(DisplayRow);
 9338            let below_edit = Some(edit_end.row() + 1);
 9339            let above_cursor =
 9340                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9341            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9342
 9343            // Place the edit popover adjacent to the edit if there is a location
 9344            // available that is onscreen and does not obscure the cursor. Otherwise,
 9345            // place it adjacent to the cursor.
 9346            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9347                .into_iter()
 9348                .flatten()
 9349                .find(|&start_row| {
 9350                    let end_row = start_row + line_count as u32;
 9351                    visible_row_range.contains(&start_row)
 9352                        && visible_row_range.contains(&end_row)
 9353                        && cursor_row
 9354                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9355                })?;
 9356
 9357            content_origin
 9358                + point(
 9359                    Pixels::from(-scroll_pixel_position.x),
 9360                    Pixels::from(
 9361                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9362                    ),
 9363                )
 9364        };
 9365
 9366        origin.x -= BORDER_WIDTH;
 9367
 9368        window.defer_draw(element, origin, 1);
 9369
 9370        // Do not return an element, since it will already be drawn due to defer_draw.
 9371        None
 9372    }
 9373
 9374    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9375        px(30.)
 9376    }
 9377
 9378    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9379        if self.read_only(cx) {
 9380            cx.theme().players().read_only()
 9381        } else {
 9382            self.style.as_ref().unwrap().local_player
 9383        }
 9384    }
 9385
 9386    fn render_edit_prediction_accept_keybind(
 9387        &self,
 9388        window: &mut Window,
 9389        cx: &mut App,
 9390    ) -> Option<AnyElement> {
 9391        let accept_binding =
 9392            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9393        let accept_keystroke = accept_binding.keystroke()?;
 9394
 9395        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9396
 9397        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9398            Color::Accent
 9399        } else {
 9400            Color::Muted
 9401        };
 9402
 9403        h_flex()
 9404            .px_0p5()
 9405            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9406            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9407            .text_size(TextSize::XSmall.rems(cx))
 9408            .child(h_flex().children(ui::render_modifiers(
 9409                accept_keystroke.modifiers(),
 9410                PlatformStyle::platform(),
 9411                Some(modifiers_color),
 9412                Some(IconSize::XSmall.rems().into()),
 9413                true,
 9414            )))
 9415            .when(is_platform_style_mac, |parent| {
 9416                parent.child(accept_keystroke.key().to_string())
 9417            })
 9418            .when(!is_platform_style_mac, |parent| {
 9419                parent.child(
 9420                    Key::new(
 9421                        util::capitalize(accept_keystroke.key()),
 9422                        Some(Color::Default),
 9423                    )
 9424                    .size(Some(IconSize::XSmall.rems().into())),
 9425                )
 9426            })
 9427            .into_any()
 9428            .into()
 9429    }
 9430
 9431    fn render_edit_prediction_line_popover(
 9432        &self,
 9433        label: impl Into<SharedString>,
 9434        icon: Option<IconName>,
 9435        window: &mut Window,
 9436        cx: &mut App,
 9437    ) -> Stateful<Div> {
 9438        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9439
 9440        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9441        let has_keybind = keybind.is_some();
 9442
 9443        h_flex()
 9444            .id("ep-line-popover")
 9445            .py_0p5()
 9446            .pl_1()
 9447            .pr(padding_right)
 9448            .gap_1()
 9449            .rounded_md()
 9450            .border_1()
 9451            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9452            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9453            .shadow_xs()
 9454            .when(!has_keybind, |el| {
 9455                let status_colors = cx.theme().status();
 9456
 9457                el.bg(status_colors.error_background)
 9458                    .border_color(status_colors.error.opacity(0.6))
 9459                    .pl_2()
 9460                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9461                    .cursor_default()
 9462                    .hoverable_tooltip(move |_window, cx| {
 9463                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9464                    })
 9465            })
 9466            .children(keybind)
 9467            .child(
 9468                Label::new(label)
 9469                    .size(LabelSize::Small)
 9470                    .when(!has_keybind, |el| {
 9471                        el.color(cx.theme().status().error.into()).strikethrough()
 9472                    }),
 9473            )
 9474            .when(!has_keybind, |el| {
 9475                el.child(
 9476                    h_flex().ml_1().child(
 9477                        Icon::new(IconName::Info)
 9478                            .size(IconSize::Small)
 9479                            .color(cx.theme().status().error.into()),
 9480                    ),
 9481                )
 9482            })
 9483            .when_some(icon, |element, icon| {
 9484                element.child(
 9485                    div()
 9486                        .mt(px(1.5))
 9487                        .child(Icon::new(icon).size(IconSize::Small)),
 9488                )
 9489            })
 9490    }
 9491
 9492    fn render_edit_prediction_jump_outside_popover(
 9493        &self,
 9494        snapshot: &BufferSnapshot,
 9495        window: &mut Window,
 9496        cx: &mut App,
 9497    ) -> Stateful<Div> {
 9498        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9499        let has_keybind = keybind.is_some();
 9500
 9501        let file_name = snapshot
 9502            .file()
 9503            .map(|file| SharedString::new(file.file_name(cx)))
 9504            .unwrap_or(SharedString::new_static("untitled"));
 9505
 9506        h_flex()
 9507            .id("ep-jump-outside-popover")
 9508            .py_1()
 9509            .px_2()
 9510            .gap_1()
 9511            .rounded_md()
 9512            .border_1()
 9513            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9514            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9515            .shadow_xs()
 9516            .when(!has_keybind, |el| {
 9517                let status_colors = cx.theme().status();
 9518
 9519                el.bg(status_colors.error_background)
 9520                    .border_color(status_colors.error.opacity(0.6))
 9521                    .pl_2()
 9522                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9523                    .cursor_default()
 9524                    .hoverable_tooltip(move |_window, cx| {
 9525                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9526                    })
 9527            })
 9528            .children(keybind)
 9529            .child(
 9530                Label::new(file_name)
 9531                    .size(LabelSize::Small)
 9532                    .buffer_font(cx)
 9533                    .when(!has_keybind, |el| {
 9534                        el.color(cx.theme().status().error.into()).strikethrough()
 9535                    }),
 9536            )
 9537            .when(!has_keybind, |el| {
 9538                el.child(
 9539                    h_flex().ml_1().child(
 9540                        Icon::new(IconName::Info)
 9541                            .size(IconSize::Small)
 9542                            .color(cx.theme().status().error.into()),
 9543                    ),
 9544                )
 9545            })
 9546            .child(
 9547                div()
 9548                    .mt(px(1.5))
 9549                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9550            )
 9551    }
 9552
 9553    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9554        let accent_color = cx.theme().colors().text_accent;
 9555        let editor_bg_color = cx.theme().colors().editor_background;
 9556        editor_bg_color.blend(accent_color.opacity(0.1))
 9557    }
 9558
 9559    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9560        let accent_color = cx.theme().colors().text_accent;
 9561        let editor_bg_color = cx.theme().colors().editor_background;
 9562        editor_bg_color.blend(accent_color.opacity(0.6))
 9563    }
 9564    fn get_prediction_provider_icon_name(
 9565        provider: &Option<RegisteredEditPredictionDelegate>,
 9566    ) -> IconName {
 9567        match provider {
 9568            Some(provider) => match provider.provider.name() {
 9569                "copilot" => IconName::Copilot,
 9570                "supermaven" => IconName::Supermaven,
 9571                _ => IconName::ZedPredict,
 9572            },
 9573            None => IconName::ZedPredict,
 9574        }
 9575    }
 9576
 9577    fn render_edit_prediction_cursor_popover(
 9578        &self,
 9579        min_width: Pixels,
 9580        max_width: Pixels,
 9581        cursor_point: Point,
 9582        style: &EditorStyle,
 9583        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9584        _window: &Window,
 9585        cx: &mut Context<Editor>,
 9586    ) -> Option<AnyElement> {
 9587        let provider = self.edit_prediction_provider.as_ref()?;
 9588        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9589
 9590        let is_refreshing = provider.provider.is_refreshing(cx);
 9591
 9592        fn pending_completion_container(icon: IconName) -> Div {
 9593            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9594        }
 9595
 9596        let completion = match &self.active_edit_prediction {
 9597            Some(prediction) => {
 9598                if !self.has_visible_completions_menu() {
 9599                    const RADIUS: Pixels = px(6.);
 9600                    const BORDER_WIDTH: Pixels = px(1.);
 9601
 9602                    return Some(
 9603                        h_flex()
 9604                            .elevation_2(cx)
 9605                            .border(BORDER_WIDTH)
 9606                            .border_color(cx.theme().colors().border)
 9607                            .when(accept_keystroke.is_none(), |el| {
 9608                                el.border_color(cx.theme().status().error)
 9609                            })
 9610                            .rounded(RADIUS)
 9611                            .rounded_tl(px(0.))
 9612                            .overflow_hidden()
 9613                            .child(div().px_1p5().child(match &prediction.completion {
 9614                                EditPrediction::MoveWithin { target, snapshot } => {
 9615                                    use text::ToPoint as _;
 9616                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9617                                    {
 9618                                        Icon::new(IconName::ZedPredictDown)
 9619                                    } else {
 9620                                        Icon::new(IconName::ZedPredictUp)
 9621                                    }
 9622                                }
 9623                                EditPrediction::MoveOutside { .. } => {
 9624                                    // TODO [zeta2] custom icon for external jump?
 9625                                    Icon::new(provider_icon)
 9626                                }
 9627                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9628                            }))
 9629                            .child(
 9630                                h_flex()
 9631                                    .gap_1()
 9632                                    .py_1()
 9633                                    .px_2()
 9634                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9635                                    .border_l_1()
 9636                                    .border_color(cx.theme().colors().border)
 9637                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9638                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9639                                        el.child(
 9640                                            Label::new("Hold")
 9641                                                .size(LabelSize::Small)
 9642                                                .when(accept_keystroke.is_none(), |el| {
 9643                                                    el.strikethrough()
 9644                                                })
 9645                                                .line_height_style(LineHeightStyle::UiLabel),
 9646                                        )
 9647                                    })
 9648                                    .id("edit_prediction_cursor_popover_keybind")
 9649                                    .when(accept_keystroke.is_none(), |el| {
 9650                                        let status_colors = cx.theme().status();
 9651
 9652                                        el.bg(status_colors.error_background)
 9653                                            .border_color(status_colors.error.opacity(0.6))
 9654                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9655                                            .cursor_default()
 9656                                            .hoverable_tooltip(move |_window, cx| {
 9657                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9658                                                    .into()
 9659                                            })
 9660                                    })
 9661                                    .when_some(
 9662                                        accept_keystroke.as_ref(),
 9663                                        |el, accept_keystroke| {
 9664                                            el.child(h_flex().children(ui::render_modifiers(
 9665                                                accept_keystroke.modifiers(),
 9666                                                PlatformStyle::platform(),
 9667                                                Some(Color::Default),
 9668                                                Some(IconSize::XSmall.rems().into()),
 9669                                                false,
 9670                                            )))
 9671                                        },
 9672                                    ),
 9673                            )
 9674                            .into_any(),
 9675                    );
 9676                }
 9677
 9678                self.render_edit_prediction_cursor_popover_preview(
 9679                    prediction,
 9680                    cursor_point,
 9681                    style,
 9682                    cx,
 9683                )?
 9684            }
 9685
 9686            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9687                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9688                    stale_completion,
 9689                    cursor_point,
 9690                    style,
 9691                    cx,
 9692                )?,
 9693
 9694                None => pending_completion_container(provider_icon)
 9695                    .child(Label::new("...").size(LabelSize::Small)),
 9696            },
 9697
 9698            None => pending_completion_container(provider_icon)
 9699                .child(Label::new("...").size(LabelSize::Small)),
 9700        };
 9701
 9702        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9703            completion
 9704                .with_animation(
 9705                    "loading-completion",
 9706                    Animation::new(Duration::from_secs(2))
 9707                        .repeat()
 9708                        .with_easing(pulsating_between(0.4, 0.8)),
 9709                    |label, delta| label.opacity(delta),
 9710                )
 9711                .into_any_element()
 9712        } else {
 9713            completion.into_any_element()
 9714        };
 9715
 9716        let has_completion = self.active_edit_prediction.is_some();
 9717
 9718        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9719        Some(
 9720            h_flex()
 9721                .min_w(min_width)
 9722                .max_w(max_width)
 9723                .flex_1()
 9724                .elevation_2(cx)
 9725                .border_color(cx.theme().colors().border)
 9726                .child(
 9727                    div()
 9728                        .flex_1()
 9729                        .py_1()
 9730                        .px_2()
 9731                        .overflow_hidden()
 9732                        .child(completion),
 9733                )
 9734                .when_some(accept_keystroke, |el, accept_keystroke| {
 9735                    if !accept_keystroke.modifiers().modified() {
 9736                        return el;
 9737                    }
 9738
 9739                    el.child(
 9740                        h_flex()
 9741                            .h_full()
 9742                            .border_l_1()
 9743                            .rounded_r_lg()
 9744                            .border_color(cx.theme().colors().border)
 9745                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9746                            .gap_1()
 9747                            .py_1()
 9748                            .px_2()
 9749                            .child(
 9750                                h_flex()
 9751                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9752                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9753                                    .child(h_flex().children(ui::render_modifiers(
 9754                                        accept_keystroke.modifiers(),
 9755                                        PlatformStyle::platform(),
 9756                                        Some(if !has_completion {
 9757                                            Color::Muted
 9758                                        } else {
 9759                                            Color::Default
 9760                                        }),
 9761                                        None,
 9762                                        false,
 9763                                    ))),
 9764                            )
 9765                            .child(Label::new("Preview").into_any_element())
 9766                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9767                    )
 9768                })
 9769                .into_any(),
 9770        )
 9771    }
 9772
 9773    fn render_edit_prediction_cursor_popover_preview(
 9774        &self,
 9775        completion: &EditPredictionState,
 9776        cursor_point: Point,
 9777        style: &EditorStyle,
 9778        cx: &mut Context<Editor>,
 9779    ) -> Option<Div> {
 9780        use text::ToPoint as _;
 9781
 9782        fn render_relative_row_jump(
 9783            prefix: impl Into<String>,
 9784            current_row: u32,
 9785            target_row: u32,
 9786        ) -> Div {
 9787            let (row_diff, arrow) = if target_row < current_row {
 9788                (current_row - target_row, IconName::ArrowUp)
 9789            } else {
 9790                (target_row - current_row, IconName::ArrowDown)
 9791            };
 9792
 9793            h_flex()
 9794                .child(
 9795                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9796                        .color(Color::Muted)
 9797                        .size(LabelSize::Small),
 9798                )
 9799                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9800        }
 9801
 9802        let supports_jump = self
 9803            .edit_prediction_provider
 9804            .as_ref()
 9805            .map(|provider| provider.provider.supports_jump_to_edit())
 9806            .unwrap_or(true);
 9807
 9808        match &completion.completion {
 9809            EditPrediction::MoveWithin {
 9810                target, snapshot, ..
 9811            } => {
 9812                if !supports_jump {
 9813                    return None;
 9814                }
 9815
 9816                Some(
 9817                    h_flex()
 9818                        .px_2()
 9819                        .gap_2()
 9820                        .flex_1()
 9821                        .child(
 9822                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9823                                Icon::new(IconName::ZedPredictDown)
 9824                            } else {
 9825                                Icon::new(IconName::ZedPredictUp)
 9826                            },
 9827                        )
 9828                        .child(Label::new("Jump to Edit")),
 9829                )
 9830            }
 9831            EditPrediction::MoveOutside { snapshot, .. } => {
 9832                let file_name = snapshot
 9833                    .file()
 9834                    .map(|file| file.file_name(cx))
 9835                    .unwrap_or("untitled");
 9836                Some(
 9837                    h_flex()
 9838                        .px_2()
 9839                        .gap_2()
 9840                        .flex_1()
 9841                        .child(Icon::new(IconName::ZedPredict))
 9842                        .child(Label::new(format!("Jump to {file_name}"))),
 9843                )
 9844            }
 9845            EditPrediction::Edit {
 9846                edits,
 9847                edit_preview,
 9848                snapshot,
 9849                display_mode: _,
 9850            } => {
 9851                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9852
 9853                let (highlighted_edits, has_more_lines) =
 9854                    if let Some(edit_preview) = edit_preview.as_ref() {
 9855                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9856                            .first_line_preview()
 9857                    } else {
 9858                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9859                    };
 9860
 9861                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9862                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9863
 9864                let preview = h_flex()
 9865                    .gap_1()
 9866                    .min_w_16()
 9867                    .child(styled_text)
 9868                    .when(has_more_lines, |parent| parent.child(""));
 9869
 9870                let left = if supports_jump && first_edit_row != cursor_point.row {
 9871                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9872                        .into_any_element()
 9873                } else {
 9874                    let icon_name =
 9875                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9876                    Icon::new(icon_name).into_any_element()
 9877                };
 9878
 9879                Some(
 9880                    h_flex()
 9881                        .h_full()
 9882                        .flex_1()
 9883                        .gap_2()
 9884                        .pr_1()
 9885                        .overflow_x_hidden()
 9886                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9887                        .child(left)
 9888                        .child(preview),
 9889                )
 9890            }
 9891        }
 9892    }
 9893
 9894    pub fn render_context_menu(
 9895        &mut self,
 9896        max_height_in_lines: u32,
 9897        window: &mut Window,
 9898        cx: &mut Context<Editor>,
 9899    ) -> Option<AnyElement> {
 9900        let menu = self.context_menu.borrow();
 9901        let menu = menu.as_ref()?;
 9902        if !menu.visible() {
 9903            return None;
 9904        };
 9905        self.style
 9906            .as_ref()
 9907            .map(|style| menu.render(style, max_height_in_lines, window, cx))
 9908    }
 9909
 9910    fn render_context_menu_aside(
 9911        &mut self,
 9912        max_size: Size<Pixels>,
 9913        window: &mut Window,
 9914        cx: &mut Context<Editor>,
 9915    ) -> Option<AnyElement> {
 9916        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9917            if menu.visible() {
 9918                menu.render_aside(max_size, window, cx)
 9919            } else {
 9920                None
 9921            }
 9922        })
 9923    }
 9924
 9925    fn hide_context_menu(
 9926        &mut self,
 9927        window: &mut Window,
 9928        cx: &mut Context<Self>,
 9929    ) -> Option<CodeContextMenu> {
 9930        cx.notify();
 9931        self.completion_tasks.clear();
 9932        let context_menu = self.context_menu.borrow_mut().take();
 9933        self.stale_edit_prediction_in_menu.take();
 9934        self.update_visible_edit_prediction(window, cx);
 9935        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9936            && let Some(completion_provider) = &self.completion_provider
 9937        {
 9938            completion_provider.selection_changed(None, window, cx);
 9939        }
 9940        context_menu
 9941    }
 9942
 9943    fn show_snippet_choices(
 9944        &mut self,
 9945        choices: &Vec<String>,
 9946        selection: Range<Anchor>,
 9947        cx: &mut Context<Self>,
 9948    ) {
 9949        let Some((_, buffer, _)) = self
 9950            .buffer()
 9951            .read(cx)
 9952            .excerpt_containing(selection.start, cx)
 9953        else {
 9954            return;
 9955        };
 9956        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9957        else {
 9958            return;
 9959        };
 9960        if buffer != end_buffer {
 9961            log::error!("expected anchor range to have matching buffer IDs");
 9962            return;
 9963        }
 9964
 9965        let id = post_inc(&mut self.next_completion_id);
 9966        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9967        let mut context_menu = self.context_menu.borrow_mut();
 9968        let old_menu = context_menu.take();
 9969        *context_menu = Some(CodeContextMenu::Completions(
 9970            CompletionsMenu::new_snippet_choices(
 9971                id,
 9972                true,
 9973                choices,
 9974                selection,
 9975                buffer,
 9976                old_menu.map(|menu| menu.primary_scroll_handle()),
 9977                snippet_sort_order,
 9978            ),
 9979        ));
 9980    }
 9981
 9982    pub fn insert_snippet(
 9983        &mut self,
 9984        insertion_ranges: &[Range<MultiBufferOffset>],
 9985        snippet: Snippet,
 9986        window: &mut Window,
 9987        cx: &mut Context<Self>,
 9988    ) -> Result<()> {
 9989        struct Tabstop<T> {
 9990            is_end_tabstop: bool,
 9991            ranges: Vec<Range<T>>,
 9992            choices: Option<Vec<String>>,
 9993        }
 9994
 9995        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9996            let snippet_text: Arc<str> = snippet.text.clone().into();
 9997            let edits = insertion_ranges
 9998                .iter()
 9999                .cloned()
10000                .map(|range| (range, snippet_text.clone()));
10001            let autoindent_mode = AutoindentMode::Block {
10002                original_indent_columns: Vec::new(),
10003            };
10004            buffer.edit(edits, Some(autoindent_mode), cx);
10005
10006            let snapshot = &*buffer.read(cx);
10007            let snippet = &snippet;
10008            snippet
10009                .tabstops
10010                .iter()
10011                .map(|tabstop| {
10012                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10013                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10014                    });
10015                    let mut tabstop_ranges = tabstop
10016                        .ranges
10017                        .iter()
10018                        .flat_map(|tabstop_range| {
10019                            let mut delta = 0_isize;
10020                            insertion_ranges.iter().map(move |insertion_range| {
10021                                let insertion_start = insertion_range.start + delta;
10022                                delta += snippet.text.len() as isize
10023                                    - (insertion_range.end - insertion_range.start) as isize;
10024
10025                                let start =
10026                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10027                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10028                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10029                            })
10030                        })
10031                        .collect::<Vec<_>>();
10032                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10033
10034                    Tabstop {
10035                        is_end_tabstop,
10036                        ranges: tabstop_ranges,
10037                        choices: tabstop.choices.clone(),
10038                    }
10039                })
10040                .collect::<Vec<_>>()
10041        });
10042        if let Some(tabstop) = tabstops.first() {
10043            self.change_selections(Default::default(), window, cx, |s| {
10044                // Reverse order so that the first range is the newest created selection.
10045                // Completions will use it and autoscroll will prioritize it.
10046                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10047            });
10048
10049            if let Some(choices) = &tabstop.choices
10050                && let Some(selection) = tabstop.ranges.first()
10051            {
10052                self.show_snippet_choices(choices, selection.clone(), cx)
10053            }
10054
10055            // If we're already at the last tabstop and it's at the end of the snippet,
10056            // we're done, we don't need to keep the state around.
10057            if !tabstop.is_end_tabstop {
10058                let choices = tabstops
10059                    .iter()
10060                    .map(|tabstop| tabstop.choices.clone())
10061                    .collect();
10062
10063                let ranges = tabstops
10064                    .into_iter()
10065                    .map(|tabstop| tabstop.ranges)
10066                    .collect::<Vec<_>>();
10067
10068                self.snippet_stack.push(SnippetState {
10069                    active_index: 0,
10070                    ranges,
10071                    choices,
10072                });
10073            }
10074
10075            // Check whether the just-entered snippet ends with an auto-closable bracket.
10076            if self.autoclose_regions.is_empty() {
10077                let snapshot = self.buffer.read(cx).snapshot(cx);
10078                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10079                    let selection_head = selection.head();
10080                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10081                        continue;
10082                    };
10083
10084                    let mut bracket_pair = None;
10085                    let max_lookup_length = scope
10086                        .brackets()
10087                        .map(|(pair, _)| {
10088                            pair.start
10089                                .as_str()
10090                                .chars()
10091                                .count()
10092                                .max(pair.end.as_str().chars().count())
10093                        })
10094                        .max();
10095                    if let Some(max_lookup_length) = max_lookup_length {
10096                        let next_text = snapshot
10097                            .chars_at(selection_head)
10098                            .take(max_lookup_length)
10099                            .collect::<String>();
10100                        let prev_text = snapshot
10101                            .reversed_chars_at(selection_head)
10102                            .take(max_lookup_length)
10103                            .collect::<String>();
10104
10105                        for (pair, enabled) in scope.brackets() {
10106                            if enabled
10107                                && pair.close
10108                                && prev_text.starts_with(pair.start.as_str())
10109                                && next_text.starts_with(pair.end.as_str())
10110                            {
10111                                bracket_pair = Some(pair.clone());
10112                                break;
10113                            }
10114                        }
10115                    }
10116
10117                    if let Some(pair) = bracket_pair {
10118                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10119                        let autoclose_enabled =
10120                            self.use_autoclose && snapshot_settings.use_autoclose;
10121                        if autoclose_enabled {
10122                            let start = snapshot.anchor_after(selection_head);
10123                            let end = snapshot.anchor_after(selection_head);
10124                            self.autoclose_regions.push(AutocloseRegion {
10125                                selection_id: selection.id,
10126                                range: start..end,
10127                                pair,
10128                            });
10129                        }
10130                    }
10131                }
10132            }
10133        }
10134        Ok(())
10135    }
10136
10137    pub fn move_to_next_snippet_tabstop(
10138        &mut self,
10139        window: &mut Window,
10140        cx: &mut Context<Self>,
10141    ) -> bool {
10142        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10143    }
10144
10145    pub fn move_to_prev_snippet_tabstop(
10146        &mut self,
10147        window: &mut Window,
10148        cx: &mut Context<Self>,
10149    ) -> bool {
10150        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10151    }
10152
10153    pub fn move_to_snippet_tabstop(
10154        &mut self,
10155        bias: Bias,
10156        window: &mut Window,
10157        cx: &mut Context<Self>,
10158    ) -> bool {
10159        if let Some(mut snippet) = self.snippet_stack.pop() {
10160            match bias {
10161                Bias::Left => {
10162                    if snippet.active_index > 0 {
10163                        snippet.active_index -= 1;
10164                    } else {
10165                        self.snippet_stack.push(snippet);
10166                        return false;
10167                    }
10168                }
10169                Bias::Right => {
10170                    if snippet.active_index + 1 < snippet.ranges.len() {
10171                        snippet.active_index += 1;
10172                    } else {
10173                        self.snippet_stack.push(snippet);
10174                        return false;
10175                    }
10176                }
10177            }
10178            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10179                self.change_selections(Default::default(), window, cx, |s| {
10180                    // Reverse order so that the first range is the newest created selection.
10181                    // Completions will use it and autoscroll will prioritize it.
10182                    s.select_ranges(current_ranges.iter().rev().cloned())
10183                });
10184
10185                if let Some(choices) = &snippet.choices[snippet.active_index]
10186                    && let Some(selection) = current_ranges.first()
10187                {
10188                    self.show_snippet_choices(choices, selection.clone(), cx);
10189                }
10190
10191                // If snippet state is not at the last tabstop, push it back on the stack
10192                if snippet.active_index + 1 < snippet.ranges.len() {
10193                    self.snippet_stack.push(snippet);
10194                }
10195                return true;
10196            }
10197        }
10198
10199        false
10200    }
10201
10202    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10203        self.transact(window, cx, |this, window, cx| {
10204            this.select_all(&SelectAll, window, cx);
10205            this.insert("", window, cx);
10206        });
10207    }
10208
10209    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10210        if self.read_only(cx) {
10211            return;
10212        }
10213        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10214        self.transact(window, cx, |this, window, cx| {
10215            this.select_autoclose_pair(window, cx);
10216
10217            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10218
10219            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10220            if !this.linked_edit_ranges.is_empty() {
10221                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10222                let snapshot = this.buffer.read(cx).snapshot(cx);
10223
10224                for selection in selections.iter() {
10225                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10226                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10227                    if selection_start.buffer_id != selection_end.buffer_id {
10228                        continue;
10229                    }
10230                    if let Some(ranges) =
10231                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10232                    {
10233                        for (buffer, entries) in ranges {
10234                            linked_ranges.entry(buffer).or_default().extend(entries);
10235                        }
10236                    }
10237                }
10238            }
10239
10240            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10241            for selection in &mut selections {
10242                if selection.is_empty() {
10243                    let old_head = selection.head();
10244                    let mut new_head =
10245                        movement::left(&display_map, old_head.to_display_point(&display_map))
10246                            .to_point(&display_map);
10247                    if let Some((buffer, line_buffer_range)) = display_map
10248                        .buffer_snapshot()
10249                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10250                    {
10251                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10252                        let indent_len = match indent_size.kind {
10253                            IndentKind::Space => {
10254                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10255                            }
10256                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10257                        };
10258                        if old_head.column <= indent_size.len && old_head.column > 0 {
10259                            let indent_len = indent_len.get();
10260                            new_head = cmp::min(
10261                                new_head,
10262                                MultiBufferPoint::new(
10263                                    old_head.row,
10264                                    ((old_head.column - 1) / indent_len) * indent_len,
10265                                ),
10266                            );
10267                        }
10268                    }
10269
10270                    selection.set_head(new_head, SelectionGoal::None);
10271                }
10272            }
10273
10274            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10275            this.insert("", window, cx);
10276            let empty_str: Arc<str> = Arc::from("");
10277            for (buffer, edits) in linked_ranges {
10278                let snapshot = buffer.read(cx).snapshot();
10279                use text::ToPoint as TP;
10280
10281                let edits = edits
10282                    .into_iter()
10283                    .map(|range| {
10284                        let end_point = TP::to_point(&range.end, &snapshot);
10285                        let mut start_point = TP::to_point(&range.start, &snapshot);
10286
10287                        if end_point == start_point {
10288                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10289                                .saturating_sub(1);
10290                            start_point =
10291                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10292                        };
10293
10294                        (start_point..end_point, empty_str.clone())
10295                    })
10296                    .sorted_by_key(|(range, _)| range.start)
10297                    .collect::<Vec<_>>();
10298                buffer.update(cx, |this, cx| {
10299                    this.edit(edits, None, cx);
10300                })
10301            }
10302            this.refresh_edit_prediction(true, false, window, cx);
10303            refresh_linked_ranges(this, window, cx);
10304        });
10305    }
10306
10307    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10308        if self.read_only(cx) {
10309            return;
10310        }
10311        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10312        self.transact(window, cx, |this, window, cx| {
10313            this.change_selections(Default::default(), window, cx, |s| {
10314                s.move_with(|map, selection| {
10315                    if selection.is_empty() {
10316                        let cursor = movement::right(map, selection.head());
10317                        selection.end = cursor;
10318                        selection.reversed = true;
10319                        selection.goal = SelectionGoal::None;
10320                    }
10321                })
10322            });
10323            this.insert("", window, cx);
10324            this.refresh_edit_prediction(true, false, window, cx);
10325        });
10326    }
10327
10328    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10329        if self.mode.is_single_line() {
10330            cx.propagate();
10331            return;
10332        }
10333
10334        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10335        if self.move_to_prev_snippet_tabstop(window, cx) {
10336            return;
10337        }
10338        self.outdent(&Outdent, window, cx);
10339    }
10340
10341    pub fn next_snippet_tabstop(
10342        &mut self,
10343        _: &NextSnippetTabstop,
10344        window: &mut Window,
10345        cx: &mut Context<Self>,
10346    ) {
10347        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10348            cx.propagate();
10349            return;
10350        }
10351
10352        if self.move_to_next_snippet_tabstop(window, cx) {
10353            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10354            return;
10355        }
10356        cx.propagate();
10357    }
10358
10359    pub fn previous_snippet_tabstop(
10360        &mut self,
10361        _: &PreviousSnippetTabstop,
10362        window: &mut Window,
10363        cx: &mut Context<Self>,
10364    ) {
10365        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10366            cx.propagate();
10367            return;
10368        }
10369
10370        if self.move_to_prev_snippet_tabstop(window, cx) {
10371            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10372            return;
10373        }
10374        cx.propagate();
10375    }
10376
10377    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10378        if self.mode.is_single_line() {
10379            cx.propagate();
10380            return;
10381        }
10382
10383        if self.move_to_next_snippet_tabstop(window, cx) {
10384            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10385            return;
10386        }
10387        if self.read_only(cx) {
10388            return;
10389        }
10390        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10391        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10392        let buffer = self.buffer.read(cx);
10393        let snapshot = buffer.snapshot(cx);
10394        let rows_iter = selections.iter().map(|s| s.head().row);
10395        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10396
10397        let has_some_cursor_in_whitespace = selections
10398            .iter()
10399            .filter(|selection| selection.is_empty())
10400            .any(|selection| {
10401                let cursor = selection.head();
10402                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10403                cursor.column < current_indent.len
10404            });
10405
10406        let mut edits = Vec::new();
10407        let mut prev_edited_row = 0;
10408        let mut row_delta = 0;
10409        for selection in &mut selections {
10410            if selection.start.row != prev_edited_row {
10411                row_delta = 0;
10412            }
10413            prev_edited_row = selection.end.row;
10414
10415            // If the selection is non-empty, then increase the indentation of the selected lines.
10416            if !selection.is_empty() {
10417                row_delta =
10418                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10419                continue;
10420            }
10421
10422            let cursor = selection.head();
10423            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10424            if let Some(suggested_indent) =
10425                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10426            {
10427                // Don't do anything if already at suggested indent
10428                // and there is any other cursor which is not
10429                if has_some_cursor_in_whitespace
10430                    && cursor.column == current_indent.len
10431                    && current_indent.len == suggested_indent.len
10432                {
10433                    continue;
10434                }
10435
10436                // Adjust line and move cursor to suggested indent
10437                // if cursor is not at suggested indent
10438                if cursor.column < suggested_indent.len
10439                    && cursor.column <= current_indent.len
10440                    && current_indent.len <= suggested_indent.len
10441                {
10442                    selection.start = Point::new(cursor.row, suggested_indent.len);
10443                    selection.end = selection.start;
10444                    if row_delta == 0 {
10445                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10446                            cursor.row,
10447                            current_indent,
10448                            suggested_indent,
10449                        ));
10450                        row_delta = suggested_indent.len - current_indent.len;
10451                    }
10452                    continue;
10453                }
10454
10455                // If current indent is more than suggested indent
10456                // only move cursor to current indent and skip indent
10457                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10458                    selection.start = Point::new(cursor.row, current_indent.len);
10459                    selection.end = selection.start;
10460                    continue;
10461                }
10462            }
10463
10464            // Otherwise, insert a hard or soft tab.
10465            let settings = buffer.language_settings_at(cursor, cx);
10466            let tab_size = if settings.hard_tabs {
10467                IndentSize::tab()
10468            } else {
10469                let tab_size = settings.tab_size.get();
10470                let indent_remainder = snapshot
10471                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10472                    .flat_map(str::chars)
10473                    .fold(row_delta % tab_size, |counter: u32, c| {
10474                        if c == '\t' {
10475                            0
10476                        } else {
10477                            (counter + 1) % tab_size
10478                        }
10479                    });
10480
10481                let chars_to_next_tab_stop = tab_size - indent_remainder;
10482                IndentSize::spaces(chars_to_next_tab_stop)
10483            };
10484            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10485            selection.end = selection.start;
10486            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10487            row_delta += tab_size.len;
10488        }
10489
10490        self.transact(window, cx, |this, window, cx| {
10491            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10492            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10493            this.refresh_edit_prediction(true, false, window, cx);
10494        });
10495    }
10496
10497    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10498        if self.read_only(cx) {
10499            return;
10500        }
10501        if self.mode.is_single_line() {
10502            cx.propagate();
10503            return;
10504        }
10505
10506        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10507        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10508        let mut prev_edited_row = 0;
10509        let mut row_delta = 0;
10510        let mut edits = Vec::new();
10511        let buffer = self.buffer.read(cx);
10512        let snapshot = buffer.snapshot(cx);
10513        for selection in &mut selections {
10514            if selection.start.row != prev_edited_row {
10515                row_delta = 0;
10516            }
10517            prev_edited_row = selection.end.row;
10518
10519            row_delta =
10520                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10521        }
10522
10523        self.transact(window, cx, |this, window, cx| {
10524            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10525            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10526        });
10527    }
10528
10529    fn indent_selection(
10530        buffer: &MultiBuffer,
10531        snapshot: &MultiBufferSnapshot,
10532        selection: &mut Selection<Point>,
10533        edits: &mut Vec<(Range<Point>, String)>,
10534        delta_for_start_row: u32,
10535        cx: &App,
10536    ) -> u32 {
10537        let settings = buffer.language_settings_at(selection.start, cx);
10538        let tab_size = settings.tab_size.get();
10539        let indent_kind = if settings.hard_tabs {
10540            IndentKind::Tab
10541        } else {
10542            IndentKind::Space
10543        };
10544        let mut start_row = selection.start.row;
10545        let mut end_row = selection.end.row + 1;
10546
10547        // If a selection ends at the beginning of a line, don't indent
10548        // that last line.
10549        if selection.end.column == 0 && selection.end.row > selection.start.row {
10550            end_row -= 1;
10551        }
10552
10553        // Avoid re-indenting a row that has already been indented by a
10554        // previous selection, but still update this selection's column
10555        // to reflect that indentation.
10556        if delta_for_start_row > 0 {
10557            start_row += 1;
10558            selection.start.column += delta_for_start_row;
10559            if selection.end.row == selection.start.row {
10560                selection.end.column += delta_for_start_row;
10561            }
10562        }
10563
10564        let mut delta_for_end_row = 0;
10565        let has_multiple_rows = start_row + 1 != end_row;
10566        for row in start_row..end_row {
10567            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10568            let indent_delta = match (current_indent.kind, indent_kind) {
10569                (IndentKind::Space, IndentKind::Space) => {
10570                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10571                    IndentSize::spaces(columns_to_next_tab_stop)
10572                }
10573                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10574                (_, IndentKind::Tab) => IndentSize::tab(),
10575            };
10576
10577            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10578                0
10579            } else {
10580                selection.start.column
10581            };
10582            let row_start = Point::new(row, start);
10583            edits.push((
10584                row_start..row_start,
10585                indent_delta.chars().collect::<String>(),
10586            ));
10587
10588            // Update this selection's endpoints to reflect the indentation.
10589            if row == selection.start.row {
10590                selection.start.column += indent_delta.len;
10591            }
10592            if row == selection.end.row {
10593                selection.end.column += indent_delta.len;
10594                delta_for_end_row = indent_delta.len;
10595            }
10596        }
10597
10598        if selection.start.row == selection.end.row {
10599            delta_for_start_row + delta_for_end_row
10600        } else {
10601            delta_for_end_row
10602        }
10603    }
10604
10605    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10606        if self.read_only(cx) {
10607            return;
10608        }
10609        if self.mode.is_single_line() {
10610            cx.propagate();
10611            return;
10612        }
10613
10614        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10615        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10616        let selections = self.selections.all::<Point>(&display_map);
10617        let mut deletion_ranges = Vec::new();
10618        let mut last_outdent = None;
10619        {
10620            let buffer = self.buffer.read(cx);
10621            let snapshot = buffer.snapshot(cx);
10622            for selection in &selections {
10623                let settings = buffer.language_settings_at(selection.start, cx);
10624                let tab_size = settings.tab_size.get();
10625                let mut rows = selection.spanned_rows(false, &display_map);
10626
10627                // Avoid re-outdenting a row that has already been outdented by a
10628                // previous selection.
10629                if let Some(last_row) = last_outdent
10630                    && last_row == rows.start
10631                {
10632                    rows.start = rows.start.next_row();
10633                }
10634                let has_multiple_rows = rows.len() > 1;
10635                for row in rows.iter_rows() {
10636                    let indent_size = snapshot.indent_size_for_line(row);
10637                    if indent_size.len > 0 {
10638                        let deletion_len = match indent_size.kind {
10639                            IndentKind::Space => {
10640                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10641                                if columns_to_prev_tab_stop == 0 {
10642                                    tab_size
10643                                } else {
10644                                    columns_to_prev_tab_stop
10645                                }
10646                            }
10647                            IndentKind::Tab => 1,
10648                        };
10649                        let start = if has_multiple_rows
10650                            || deletion_len > selection.start.column
10651                            || indent_size.len < selection.start.column
10652                        {
10653                            0
10654                        } else {
10655                            selection.start.column - deletion_len
10656                        };
10657                        deletion_ranges.push(
10658                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10659                        );
10660                        last_outdent = Some(row);
10661                    }
10662                }
10663            }
10664        }
10665
10666        self.transact(window, cx, |this, window, cx| {
10667            this.buffer.update(cx, |buffer, cx| {
10668                let empty_str: Arc<str> = Arc::default();
10669                buffer.edit(
10670                    deletion_ranges
10671                        .into_iter()
10672                        .map(|range| (range, empty_str.clone())),
10673                    None,
10674                    cx,
10675                );
10676            });
10677            let selections = this
10678                .selections
10679                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10680            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10681        });
10682    }
10683
10684    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10685        if self.read_only(cx) {
10686            return;
10687        }
10688        if self.mode.is_single_line() {
10689            cx.propagate();
10690            return;
10691        }
10692
10693        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10694        let selections = self
10695            .selections
10696            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10697            .into_iter()
10698            .map(|s| s.range());
10699
10700        self.transact(window, cx, |this, window, cx| {
10701            this.buffer.update(cx, |buffer, cx| {
10702                buffer.autoindent_ranges(selections, cx);
10703            });
10704            let selections = this
10705                .selections
10706                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10707            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10708        });
10709    }
10710
10711    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10712        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10713        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10714        let selections = self.selections.all::<Point>(&display_map);
10715
10716        let mut new_cursors = Vec::new();
10717        let mut edit_ranges = Vec::new();
10718        let mut selections = selections.iter().peekable();
10719        while let Some(selection) = selections.next() {
10720            let mut rows = selection.spanned_rows(false, &display_map);
10721
10722            // Accumulate contiguous regions of rows that we want to delete.
10723            while let Some(next_selection) = selections.peek() {
10724                let next_rows = next_selection.spanned_rows(false, &display_map);
10725                if next_rows.start <= rows.end {
10726                    rows.end = next_rows.end;
10727                    selections.next().unwrap();
10728                } else {
10729                    break;
10730                }
10731            }
10732
10733            let buffer = display_map.buffer_snapshot();
10734            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10735            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10736                // If there's a line after the range, delete the \n from the end of the row range
10737                (
10738                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10739                    rows.end,
10740                )
10741            } else {
10742                // If there isn't a line after the range, delete the \n from the line before the
10743                // start of the row range
10744                edit_start = edit_start.saturating_sub_usize(1);
10745                (buffer.len(), rows.start.previous_row())
10746            };
10747
10748            let text_layout_details = self.text_layout_details(window);
10749            let x = display_map.x_for_display_point(
10750                selection.head().to_display_point(&display_map),
10751                &text_layout_details,
10752            );
10753            let row = Point::new(target_row.0, 0)
10754                .to_display_point(&display_map)
10755                .row();
10756            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10757
10758            new_cursors.push((
10759                selection.id,
10760                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10761                SelectionGoal::None,
10762            ));
10763            edit_ranges.push(edit_start..edit_end);
10764        }
10765
10766        self.transact(window, cx, |this, window, cx| {
10767            let buffer = this.buffer.update(cx, |buffer, cx| {
10768                let empty_str: Arc<str> = Arc::default();
10769                buffer.edit(
10770                    edit_ranges
10771                        .into_iter()
10772                        .map(|range| (range, empty_str.clone())),
10773                    None,
10774                    cx,
10775                );
10776                buffer.snapshot(cx)
10777            });
10778            let new_selections = new_cursors
10779                .into_iter()
10780                .map(|(id, cursor, goal)| {
10781                    let cursor = cursor.to_point(&buffer);
10782                    Selection {
10783                        id,
10784                        start: cursor,
10785                        end: cursor,
10786                        reversed: false,
10787                        goal,
10788                    }
10789                })
10790                .collect();
10791
10792            this.change_selections(Default::default(), window, cx, |s| {
10793                s.select(new_selections);
10794            });
10795        });
10796    }
10797
10798    pub fn join_lines_impl(
10799        &mut self,
10800        insert_whitespace: bool,
10801        window: &mut Window,
10802        cx: &mut Context<Self>,
10803    ) {
10804        if self.read_only(cx) {
10805            return;
10806        }
10807        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10808        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10809            let start = MultiBufferRow(selection.start.row);
10810            // Treat single line selections as if they include the next line. Otherwise this action
10811            // would do nothing for single line selections individual cursors.
10812            let end = if selection.start.row == selection.end.row {
10813                MultiBufferRow(selection.start.row + 1)
10814            } else {
10815                MultiBufferRow(selection.end.row)
10816            };
10817
10818            if let Some(last_row_range) = row_ranges.last_mut()
10819                && start <= last_row_range.end
10820            {
10821                last_row_range.end = end;
10822                continue;
10823            }
10824            row_ranges.push(start..end);
10825        }
10826
10827        let snapshot = self.buffer.read(cx).snapshot(cx);
10828        let mut cursor_positions = Vec::new();
10829        for row_range in &row_ranges {
10830            let anchor = snapshot.anchor_before(Point::new(
10831                row_range.end.previous_row().0,
10832                snapshot.line_len(row_range.end.previous_row()),
10833            ));
10834            cursor_positions.push(anchor..anchor);
10835        }
10836
10837        self.transact(window, cx, |this, window, cx| {
10838            for row_range in row_ranges.into_iter().rev() {
10839                for row in row_range.iter_rows().rev() {
10840                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10841                    let next_line_row = row.next_row();
10842                    let indent = snapshot.indent_size_for_line(next_line_row);
10843                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10844
10845                    let replace =
10846                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10847                            " "
10848                        } else {
10849                            ""
10850                        };
10851
10852                    this.buffer.update(cx, |buffer, cx| {
10853                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10854                    });
10855                }
10856            }
10857
10858            this.change_selections(Default::default(), window, cx, |s| {
10859                s.select_anchor_ranges(cursor_positions)
10860            });
10861        });
10862    }
10863
10864    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10865        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10866        self.join_lines_impl(true, window, cx);
10867    }
10868
10869    pub fn sort_lines_case_sensitive(
10870        &mut self,
10871        _: &SortLinesCaseSensitive,
10872        window: &mut Window,
10873        cx: &mut Context<Self>,
10874    ) {
10875        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10876    }
10877
10878    pub fn sort_lines_by_length(
10879        &mut self,
10880        _: &SortLinesByLength,
10881        window: &mut Window,
10882        cx: &mut Context<Self>,
10883    ) {
10884        self.manipulate_immutable_lines(window, cx, |lines| {
10885            lines.sort_by_key(|&line| line.chars().count())
10886        })
10887    }
10888
10889    pub fn sort_lines_case_insensitive(
10890        &mut self,
10891        _: &SortLinesCaseInsensitive,
10892        window: &mut Window,
10893        cx: &mut Context<Self>,
10894    ) {
10895        self.manipulate_immutable_lines(window, cx, |lines| {
10896            lines.sort_by_key(|line| line.to_lowercase())
10897        })
10898    }
10899
10900    pub fn unique_lines_case_insensitive(
10901        &mut self,
10902        _: &UniqueLinesCaseInsensitive,
10903        window: &mut Window,
10904        cx: &mut Context<Self>,
10905    ) {
10906        self.manipulate_immutable_lines(window, cx, |lines| {
10907            let mut seen = HashSet::default();
10908            lines.retain(|line| seen.insert(line.to_lowercase()));
10909        })
10910    }
10911
10912    pub fn unique_lines_case_sensitive(
10913        &mut self,
10914        _: &UniqueLinesCaseSensitive,
10915        window: &mut Window,
10916        cx: &mut Context<Self>,
10917    ) {
10918        self.manipulate_immutable_lines(window, cx, |lines| {
10919            let mut seen = HashSet::default();
10920            lines.retain(|line| seen.insert(*line));
10921        })
10922    }
10923
10924    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10925        let snapshot = self.buffer.read(cx).snapshot(cx);
10926        for selection in self.selections.disjoint_anchors_arc().iter() {
10927            if snapshot
10928                .language_at(selection.start)
10929                .and_then(|lang| lang.config().wrap_characters.as_ref())
10930                .is_some()
10931            {
10932                return true;
10933            }
10934        }
10935        false
10936    }
10937
10938    fn wrap_selections_in_tag(
10939        &mut self,
10940        _: &WrapSelectionsInTag,
10941        window: &mut Window,
10942        cx: &mut Context<Self>,
10943    ) {
10944        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10945
10946        let snapshot = self.buffer.read(cx).snapshot(cx);
10947
10948        let mut edits = Vec::new();
10949        let mut boundaries = Vec::new();
10950
10951        for selection in self
10952            .selections
10953            .all_adjusted(&self.display_snapshot(cx))
10954            .iter()
10955        {
10956            let Some(wrap_config) = snapshot
10957                .language_at(selection.start)
10958                .and_then(|lang| lang.config().wrap_characters.clone())
10959            else {
10960                continue;
10961            };
10962
10963            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10964            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10965
10966            let start_before = snapshot.anchor_before(selection.start);
10967            let end_after = snapshot.anchor_after(selection.end);
10968
10969            edits.push((start_before..start_before, open_tag));
10970            edits.push((end_after..end_after, close_tag));
10971
10972            boundaries.push((
10973                start_before,
10974                end_after,
10975                wrap_config.start_prefix.len(),
10976                wrap_config.end_suffix.len(),
10977            ));
10978        }
10979
10980        if edits.is_empty() {
10981            return;
10982        }
10983
10984        self.transact(window, cx, |this, window, cx| {
10985            let buffer = this.buffer.update(cx, |buffer, cx| {
10986                buffer.edit(edits, None, cx);
10987                buffer.snapshot(cx)
10988            });
10989
10990            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10991            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10992                boundaries.into_iter()
10993            {
10994                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10995                let close_offset = end_after
10996                    .to_offset(&buffer)
10997                    .saturating_sub_usize(end_suffix_len);
10998                new_selections.push(open_offset..open_offset);
10999                new_selections.push(close_offset..close_offset);
11000            }
11001
11002            this.change_selections(Default::default(), window, cx, |s| {
11003                s.select_ranges(new_selections);
11004            });
11005
11006            this.request_autoscroll(Autoscroll::fit(), cx);
11007        });
11008    }
11009
11010    pub fn toggle_read_only(&mut self, _: &ToggleReadOnly, _: &mut Window, cx: &mut Context<Self>) {
11011        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11012            buffer.update(cx, |buffer, cx| {
11013                buffer.set_capability(
11014                    match buffer.capability() {
11015                        Capability::ReadWrite => Capability::Read,
11016                        Capability::Read => Capability::ReadWrite,
11017                        Capability::ReadOnly => Capability::ReadOnly,
11018                    },
11019                    cx,
11020                );
11021            })
11022        }
11023    }
11024
11025    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11026        let Some(project) = self.project.clone() else {
11027            return;
11028        };
11029        self.reload(project, window, cx)
11030            .detach_and_notify_err(window, cx);
11031    }
11032
11033    pub fn restore_file(
11034        &mut self,
11035        _: &::git::RestoreFile,
11036        window: &mut Window,
11037        cx: &mut Context<Self>,
11038    ) {
11039        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11040        let mut buffer_ids = HashSet::default();
11041        let snapshot = self.buffer().read(cx).snapshot(cx);
11042        for selection in self
11043            .selections
11044            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11045        {
11046            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11047        }
11048
11049        let buffer = self.buffer().read(cx);
11050        let ranges = buffer_ids
11051            .into_iter()
11052            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11053            .collect::<Vec<_>>();
11054
11055        self.restore_hunks_in_ranges(ranges, window, cx);
11056    }
11057
11058    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11059        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11060        let selections = self
11061            .selections
11062            .all(&self.display_snapshot(cx))
11063            .into_iter()
11064            .map(|s| s.range())
11065            .collect();
11066        self.restore_hunks_in_ranges(selections, window, cx);
11067    }
11068
11069    pub fn restore_hunks_in_ranges(
11070        &mut self,
11071        ranges: Vec<Range<Point>>,
11072        window: &mut Window,
11073        cx: &mut Context<Editor>,
11074    ) {
11075        let mut revert_changes = HashMap::default();
11076        let chunk_by = self
11077            .snapshot(window, cx)
11078            .hunks_for_ranges(ranges)
11079            .into_iter()
11080            .chunk_by(|hunk| hunk.buffer_id);
11081        for (buffer_id, hunks) in &chunk_by {
11082            let hunks = hunks.collect::<Vec<_>>();
11083            for hunk in &hunks {
11084                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11085            }
11086            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11087        }
11088        drop(chunk_by);
11089        if !revert_changes.is_empty() {
11090            self.transact(window, cx, |editor, window, cx| {
11091                editor.restore(revert_changes, window, cx);
11092            });
11093        }
11094    }
11095
11096    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11097        if let Some(status) = self
11098            .addons
11099            .iter()
11100            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11101        {
11102            return Some(status);
11103        }
11104        self.project
11105            .as_ref()?
11106            .read(cx)
11107            .status_for_buffer_id(buffer_id, cx)
11108    }
11109
11110    pub fn open_active_item_in_terminal(
11111        &mut self,
11112        _: &OpenInTerminal,
11113        window: &mut Window,
11114        cx: &mut Context<Self>,
11115    ) {
11116        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11117            let project_path = buffer.read(cx).project_path(cx)?;
11118            let project = self.project()?.read(cx);
11119            let entry = project.entry_for_path(&project_path, cx)?;
11120            let parent = match &entry.canonical_path {
11121                Some(canonical_path) => canonical_path.to_path_buf(),
11122                None => project.absolute_path(&project_path, cx)?,
11123            }
11124            .parent()?
11125            .to_path_buf();
11126            Some(parent)
11127        }) {
11128            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11129        }
11130    }
11131
11132    fn set_breakpoint_context_menu(
11133        &mut self,
11134        display_row: DisplayRow,
11135        position: Option<Anchor>,
11136        clicked_point: gpui::Point<Pixels>,
11137        window: &mut Window,
11138        cx: &mut Context<Self>,
11139    ) {
11140        let source = self
11141            .buffer
11142            .read(cx)
11143            .snapshot(cx)
11144            .anchor_before(Point::new(display_row.0, 0u32));
11145
11146        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11147
11148        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11149            self,
11150            source,
11151            clicked_point,
11152            context_menu,
11153            window,
11154            cx,
11155        );
11156    }
11157
11158    fn add_edit_breakpoint_block(
11159        &mut self,
11160        anchor: Anchor,
11161        breakpoint: &Breakpoint,
11162        edit_action: BreakpointPromptEditAction,
11163        window: &mut Window,
11164        cx: &mut Context<Self>,
11165    ) {
11166        let weak_editor = cx.weak_entity();
11167        let bp_prompt = cx.new(|cx| {
11168            BreakpointPromptEditor::new(
11169                weak_editor,
11170                anchor,
11171                breakpoint.clone(),
11172                edit_action,
11173                window,
11174                cx,
11175            )
11176        });
11177
11178        let height = bp_prompt.update(cx, |this, cx| {
11179            this.prompt
11180                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11181        });
11182        let cloned_prompt = bp_prompt.clone();
11183        let blocks = vec![BlockProperties {
11184            style: BlockStyle::Sticky,
11185            placement: BlockPlacement::Above(anchor),
11186            height: Some(height),
11187            render: Arc::new(move |cx| {
11188                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11189                cloned_prompt.clone().into_any_element()
11190            }),
11191            priority: 0,
11192        }];
11193
11194        let focus_handle = bp_prompt.focus_handle(cx);
11195        window.focus(&focus_handle, cx);
11196
11197        let block_ids = self.insert_blocks(blocks, None, cx);
11198        bp_prompt.update(cx, |prompt, _| {
11199            prompt.add_block_ids(block_ids);
11200        });
11201    }
11202
11203    pub(crate) fn breakpoint_at_row(
11204        &self,
11205        row: u32,
11206        window: &mut Window,
11207        cx: &mut Context<Self>,
11208    ) -> Option<(Anchor, Breakpoint)> {
11209        let snapshot = self.snapshot(window, cx);
11210        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11211
11212        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11213    }
11214
11215    pub(crate) fn breakpoint_at_anchor(
11216        &self,
11217        breakpoint_position: Anchor,
11218        snapshot: &EditorSnapshot,
11219        cx: &mut Context<Self>,
11220    ) -> Option<(Anchor, Breakpoint)> {
11221        let buffer = self
11222            .buffer
11223            .read(cx)
11224            .buffer_for_anchor(breakpoint_position, cx)?;
11225
11226        let enclosing_excerpt = breakpoint_position.excerpt_id;
11227        let buffer_snapshot = buffer.read(cx).snapshot();
11228
11229        let row = buffer_snapshot
11230            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11231            .row;
11232
11233        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11234        let anchor_end = snapshot
11235            .buffer_snapshot()
11236            .anchor_after(Point::new(row, line_len));
11237
11238        self.breakpoint_store
11239            .as_ref()?
11240            .read_with(cx, |breakpoint_store, cx| {
11241                breakpoint_store
11242                    .breakpoints(
11243                        &buffer,
11244                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11245                        &buffer_snapshot,
11246                        cx,
11247                    )
11248                    .next()
11249                    .and_then(|(bp, _)| {
11250                        let breakpoint_row = buffer_snapshot
11251                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11252                            .row;
11253
11254                        if breakpoint_row == row {
11255                            snapshot
11256                                .buffer_snapshot()
11257                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11258                                .map(|position| (position, bp.bp.clone()))
11259                        } else {
11260                            None
11261                        }
11262                    })
11263            })
11264    }
11265
11266    pub fn edit_log_breakpoint(
11267        &mut self,
11268        _: &EditLogBreakpoint,
11269        window: &mut Window,
11270        cx: &mut Context<Self>,
11271    ) {
11272        if self.breakpoint_store.is_none() {
11273            return;
11274        }
11275
11276        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11277            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11278                message: None,
11279                state: BreakpointState::Enabled,
11280                condition: None,
11281                hit_condition: None,
11282            });
11283
11284            self.add_edit_breakpoint_block(
11285                anchor,
11286                &breakpoint,
11287                BreakpointPromptEditAction::Log,
11288                window,
11289                cx,
11290            );
11291        }
11292    }
11293
11294    fn breakpoints_at_cursors(
11295        &self,
11296        window: &mut Window,
11297        cx: &mut Context<Self>,
11298    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11299        let snapshot = self.snapshot(window, cx);
11300        let cursors = self
11301            .selections
11302            .disjoint_anchors_arc()
11303            .iter()
11304            .map(|selection| {
11305                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11306
11307                let breakpoint_position = self
11308                    .breakpoint_at_row(cursor_position.row, window, cx)
11309                    .map(|bp| bp.0)
11310                    .unwrap_or_else(|| {
11311                        snapshot
11312                            .display_snapshot
11313                            .buffer_snapshot()
11314                            .anchor_after(Point::new(cursor_position.row, 0))
11315                    });
11316
11317                let breakpoint = self
11318                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11319                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11320
11321                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11322            })
11323            // 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.
11324            .collect::<HashMap<Anchor, _>>();
11325
11326        cursors.into_iter().collect()
11327    }
11328
11329    pub fn enable_breakpoint(
11330        &mut self,
11331        _: &crate::actions::EnableBreakpoint,
11332        window: &mut Window,
11333        cx: &mut Context<Self>,
11334    ) {
11335        if self.breakpoint_store.is_none() {
11336            return;
11337        }
11338
11339        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11340            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11341                continue;
11342            };
11343            self.edit_breakpoint_at_anchor(
11344                anchor,
11345                breakpoint,
11346                BreakpointEditAction::InvertState,
11347                cx,
11348            );
11349        }
11350    }
11351
11352    pub fn disable_breakpoint(
11353        &mut self,
11354        _: &crate::actions::DisableBreakpoint,
11355        window: &mut Window,
11356        cx: &mut Context<Self>,
11357    ) {
11358        if self.breakpoint_store.is_none() {
11359            return;
11360        }
11361
11362        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11363            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11364                continue;
11365            };
11366            self.edit_breakpoint_at_anchor(
11367                anchor,
11368                breakpoint,
11369                BreakpointEditAction::InvertState,
11370                cx,
11371            );
11372        }
11373    }
11374
11375    pub fn toggle_breakpoint(
11376        &mut self,
11377        _: &crate::actions::ToggleBreakpoint,
11378        window: &mut Window,
11379        cx: &mut Context<Self>,
11380    ) {
11381        if self.breakpoint_store.is_none() {
11382            return;
11383        }
11384
11385        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11386            if let Some(breakpoint) = breakpoint {
11387                self.edit_breakpoint_at_anchor(
11388                    anchor,
11389                    breakpoint,
11390                    BreakpointEditAction::Toggle,
11391                    cx,
11392                );
11393            } else {
11394                self.edit_breakpoint_at_anchor(
11395                    anchor,
11396                    Breakpoint::new_standard(),
11397                    BreakpointEditAction::Toggle,
11398                    cx,
11399                );
11400            }
11401        }
11402    }
11403
11404    pub fn edit_breakpoint_at_anchor(
11405        &mut self,
11406        breakpoint_position: Anchor,
11407        breakpoint: Breakpoint,
11408        edit_action: BreakpointEditAction,
11409        cx: &mut Context<Self>,
11410    ) {
11411        let Some(breakpoint_store) = &self.breakpoint_store else {
11412            return;
11413        };
11414
11415        let Some(buffer) = self
11416            .buffer
11417            .read(cx)
11418            .buffer_for_anchor(breakpoint_position, cx)
11419        else {
11420            return;
11421        };
11422
11423        breakpoint_store.update(cx, |breakpoint_store, cx| {
11424            breakpoint_store.toggle_breakpoint(
11425                buffer,
11426                BreakpointWithPosition {
11427                    position: breakpoint_position.text_anchor,
11428                    bp: breakpoint,
11429                },
11430                edit_action,
11431                cx,
11432            );
11433        });
11434
11435        cx.notify();
11436    }
11437
11438    #[cfg(any(test, feature = "test-support"))]
11439    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11440        self.breakpoint_store.clone()
11441    }
11442
11443    pub fn prepare_restore_change(
11444        &self,
11445        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11446        hunk: &MultiBufferDiffHunk,
11447        cx: &mut App,
11448    ) -> Option<()> {
11449        if hunk.is_created_file() {
11450            return None;
11451        }
11452        let buffer = self.buffer.read(cx);
11453        let diff = buffer.diff_for(hunk.buffer_id)?;
11454        let buffer = buffer.buffer(hunk.buffer_id)?;
11455        let buffer = buffer.read(cx);
11456        let original_text = diff
11457            .read(cx)
11458            .base_text()
11459            .as_rope()
11460            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11461        let buffer_snapshot = buffer.snapshot();
11462        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11463        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11464            probe
11465                .0
11466                .start
11467                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11468                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11469        }) {
11470            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11471            Some(())
11472        } else {
11473            None
11474        }
11475    }
11476
11477    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11478        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11479    }
11480
11481    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11482        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11483    }
11484
11485    pub fn rotate_selections_forward(
11486        &mut self,
11487        _: &RotateSelectionsForward,
11488        window: &mut Window,
11489        cx: &mut Context<Self>,
11490    ) {
11491        self.rotate_selections(window, cx, false)
11492    }
11493
11494    pub fn rotate_selections_backward(
11495        &mut self,
11496        _: &RotateSelectionsBackward,
11497        window: &mut Window,
11498        cx: &mut Context<Self>,
11499    ) {
11500        self.rotate_selections(window, cx, true)
11501    }
11502
11503    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11504        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11505        let display_snapshot = self.display_snapshot(cx);
11506        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11507
11508        if selections.len() < 2 {
11509            return;
11510        }
11511
11512        let (edits, new_selections) = {
11513            let buffer = self.buffer.read(cx).read(cx);
11514            let has_selections = selections.iter().any(|s| !s.is_empty());
11515            if has_selections {
11516                let mut selected_texts: Vec<String> = selections
11517                    .iter()
11518                    .map(|selection| {
11519                        buffer
11520                            .text_for_range(selection.start..selection.end)
11521                            .collect()
11522                    })
11523                    .collect();
11524
11525                if reverse {
11526                    selected_texts.rotate_left(1);
11527                } else {
11528                    selected_texts.rotate_right(1);
11529                }
11530
11531                let mut offset_delta: i64 = 0;
11532                let mut new_selections = Vec::new();
11533                let edits: Vec<_> = selections
11534                    .iter()
11535                    .zip(selected_texts.iter())
11536                    .map(|(selection, new_text)| {
11537                        let old_len = (selection.end.0 - selection.start.0) as i64;
11538                        let new_len = new_text.len() as i64;
11539                        let adjusted_start =
11540                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11541                        let adjusted_end =
11542                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11543
11544                        new_selections.push(Selection {
11545                            id: selection.id,
11546                            start: adjusted_start,
11547                            end: adjusted_end,
11548                            reversed: selection.reversed,
11549                            goal: selection.goal,
11550                        });
11551
11552                        offset_delta += new_len - old_len;
11553                        (selection.start..selection.end, new_text.clone())
11554                    })
11555                    .collect();
11556                (edits, new_selections)
11557            } else {
11558                let mut all_rows: Vec<u32> = selections
11559                    .iter()
11560                    .map(|selection| buffer.offset_to_point(selection.start).row)
11561                    .collect();
11562                all_rows.sort_unstable();
11563                all_rows.dedup();
11564
11565                if all_rows.len() < 2 {
11566                    return;
11567                }
11568
11569                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11570                    .iter()
11571                    .map(|&row| {
11572                        let start = Point::new(row, 0);
11573                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11574                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11575                    })
11576                    .collect();
11577
11578                let mut line_texts: Vec<String> = line_ranges
11579                    .iter()
11580                    .map(|range| buffer.text_for_range(range.clone()).collect())
11581                    .collect();
11582
11583                if reverse {
11584                    line_texts.rotate_left(1);
11585                } else {
11586                    line_texts.rotate_right(1);
11587                }
11588
11589                let edits = line_ranges
11590                    .iter()
11591                    .zip(line_texts.iter())
11592                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11593                    .collect();
11594
11595                let num_rows = all_rows.len();
11596                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11597                    .iter()
11598                    .enumerate()
11599                    .map(|(i, &row)| (row, i))
11600                    .collect();
11601
11602                // Compute new line start offsets after rotation (handles CRLF)
11603                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11604                let first_line_start = line_ranges[0].start.0;
11605                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11606                for text in line_texts.iter().take(num_rows - 1) {
11607                    let prev_start = *new_line_starts.last().unwrap();
11608                    new_line_starts.push(prev_start + text.len() + newline_len);
11609                }
11610
11611                let new_selections = selections
11612                    .iter()
11613                    .map(|selection| {
11614                        let point = buffer.offset_to_point(selection.start);
11615                        let old_index = row_to_index[&point.row];
11616                        let new_index = if reverse {
11617                            (old_index + num_rows - 1) % num_rows
11618                        } else {
11619                            (old_index + 1) % num_rows
11620                        };
11621                        let new_offset =
11622                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11623                        Selection {
11624                            id: selection.id,
11625                            start: new_offset,
11626                            end: new_offset,
11627                            reversed: selection.reversed,
11628                            goal: selection.goal,
11629                        }
11630                    })
11631                    .collect();
11632
11633                (edits, new_selections)
11634            }
11635        };
11636
11637        self.transact(window, cx, |this, window, cx| {
11638            this.buffer.update(cx, |buffer, cx| {
11639                buffer.edit(edits, None, cx);
11640            });
11641            this.change_selections(Default::default(), window, cx, |s| {
11642                s.select(new_selections);
11643            });
11644        });
11645    }
11646
11647    fn manipulate_lines<M>(
11648        &mut self,
11649        window: &mut Window,
11650        cx: &mut Context<Self>,
11651        mut manipulate: M,
11652    ) where
11653        M: FnMut(&str) -> LineManipulationResult,
11654    {
11655        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11656
11657        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11658        let buffer = self.buffer.read(cx).snapshot(cx);
11659
11660        let mut edits = Vec::new();
11661
11662        let selections = self.selections.all::<Point>(&display_map);
11663        let mut selections = selections.iter().peekable();
11664        let mut contiguous_row_selections = Vec::new();
11665        let mut new_selections = Vec::new();
11666        let mut added_lines = 0;
11667        let mut removed_lines = 0;
11668
11669        while let Some(selection) = selections.next() {
11670            let (start_row, end_row) = consume_contiguous_rows(
11671                &mut contiguous_row_selections,
11672                selection,
11673                &display_map,
11674                &mut selections,
11675            );
11676
11677            let start_point = Point::new(start_row.0, 0);
11678            let end_point = Point::new(
11679                end_row.previous_row().0,
11680                buffer.line_len(end_row.previous_row()),
11681            );
11682            let text = buffer
11683                .text_for_range(start_point..end_point)
11684                .collect::<String>();
11685
11686            let LineManipulationResult {
11687                new_text,
11688                line_count_before,
11689                line_count_after,
11690            } = manipulate(&text);
11691
11692            edits.push((start_point..end_point, new_text));
11693
11694            // Selections must change based on added and removed line count
11695            let start_row =
11696                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11697            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11698            new_selections.push(Selection {
11699                id: selection.id,
11700                start: start_row,
11701                end: end_row,
11702                goal: SelectionGoal::None,
11703                reversed: selection.reversed,
11704            });
11705
11706            if line_count_after > line_count_before {
11707                added_lines += line_count_after - line_count_before;
11708            } else if line_count_before > line_count_after {
11709                removed_lines += line_count_before - line_count_after;
11710            }
11711        }
11712
11713        self.transact(window, cx, |this, window, cx| {
11714            let buffer = this.buffer.update(cx, |buffer, cx| {
11715                buffer.edit(edits, None, cx);
11716                buffer.snapshot(cx)
11717            });
11718
11719            // Recalculate offsets on newly edited buffer
11720            let new_selections = new_selections
11721                .iter()
11722                .map(|s| {
11723                    let start_point = Point::new(s.start.0, 0);
11724                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11725                    Selection {
11726                        id: s.id,
11727                        start: buffer.point_to_offset(start_point),
11728                        end: buffer.point_to_offset(end_point),
11729                        goal: s.goal,
11730                        reversed: s.reversed,
11731                    }
11732                })
11733                .collect();
11734
11735            this.change_selections(Default::default(), window, cx, |s| {
11736                s.select(new_selections);
11737            });
11738
11739            this.request_autoscroll(Autoscroll::fit(), cx);
11740        });
11741    }
11742
11743    fn manipulate_immutable_lines<Fn>(
11744        &mut self,
11745        window: &mut Window,
11746        cx: &mut Context<Self>,
11747        mut callback: Fn,
11748    ) where
11749        Fn: FnMut(&mut Vec<&str>),
11750    {
11751        self.manipulate_lines(window, cx, |text| {
11752            let mut lines: Vec<&str> = text.split('\n').collect();
11753            let line_count_before = lines.len();
11754
11755            callback(&mut lines);
11756
11757            LineManipulationResult {
11758                new_text: lines.join("\n"),
11759                line_count_before,
11760                line_count_after: lines.len(),
11761            }
11762        });
11763    }
11764
11765    fn manipulate_mutable_lines<Fn>(
11766        &mut self,
11767        window: &mut Window,
11768        cx: &mut Context<Self>,
11769        mut callback: Fn,
11770    ) where
11771        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11772    {
11773        self.manipulate_lines(window, cx, |text| {
11774            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11775            let line_count_before = lines.len();
11776
11777            callback(&mut lines);
11778
11779            LineManipulationResult {
11780                new_text: lines.join("\n"),
11781                line_count_before,
11782                line_count_after: lines.len(),
11783            }
11784        });
11785    }
11786
11787    pub fn convert_indentation_to_spaces(
11788        &mut self,
11789        _: &ConvertIndentationToSpaces,
11790        window: &mut Window,
11791        cx: &mut Context<Self>,
11792    ) {
11793        let settings = self.buffer.read(cx).language_settings(cx);
11794        let tab_size = settings.tab_size.get() as usize;
11795
11796        self.manipulate_mutable_lines(window, cx, |lines| {
11797            // Allocates a reasonably sized scratch buffer once for the whole loop
11798            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11799            // Avoids recomputing spaces that could be inserted many times
11800            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11801                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11802                .collect();
11803
11804            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11805                let mut chars = line.as_ref().chars();
11806                let mut col = 0;
11807                let mut changed = false;
11808
11809                for ch in chars.by_ref() {
11810                    match ch {
11811                        ' ' => {
11812                            reindented_line.push(' ');
11813                            col += 1;
11814                        }
11815                        '\t' => {
11816                            // \t are converted to spaces depending on the current column
11817                            let spaces_len = tab_size - (col % tab_size);
11818                            reindented_line.extend(&space_cache[spaces_len - 1]);
11819                            col += spaces_len;
11820                            changed = true;
11821                        }
11822                        _ => {
11823                            // If we dont append before break, the character is consumed
11824                            reindented_line.push(ch);
11825                            break;
11826                        }
11827                    }
11828                }
11829
11830                if !changed {
11831                    reindented_line.clear();
11832                    continue;
11833                }
11834                // Append the rest of the line and replace old reference with new one
11835                reindented_line.extend(chars);
11836                *line = Cow::Owned(reindented_line.clone());
11837                reindented_line.clear();
11838            }
11839        });
11840    }
11841
11842    pub fn convert_indentation_to_tabs(
11843        &mut self,
11844        _: &ConvertIndentationToTabs,
11845        window: &mut Window,
11846        cx: &mut Context<Self>,
11847    ) {
11848        let settings = self.buffer.read(cx).language_settings(cx);
11849        let tab_size = settings.tab_size.get() as usize;
11850
11851        self.manipulate_mutable_lines(window, cx, |lines| {
11852            // Allocates a reasonably sized buffer once for the whole loop
11853            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11854            // Avoids recomputing spaces that could be inserted many times
11855            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11856                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11857                .collect();
11858
11859            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11860                let mut chars = line.chars();
11861                let mut spaces_count = 0;
11862                let mut first_non_indent_char = None;
11863                let mut changed = false;
11864
11865                for ch in chars.by_ref() {
11866                    match ch {
11867                        ' ' => {
11868                            // Keep track of spaces. Append \t when we reach tab_size
11869                            spaces_count += 1;
11870                            changed = true;
11871                            if spaces_count == tab_size {
11872                                reindented_line.push('\t');
11873                                spaces_count = 0;
11874                            }
11875                        }
11876                        '\t' => {
11877                            reindented_line.push('\t');
11878                            spaces_count = 0;
11879                        }
11880                        _ => {
11881                            // Dont append it yet, we might have remaining spaces
11882                            first_non_indent_char = Some(ch);
11883                            break;
11884                        }
11885                    }
11886                }
11887
11888                if !changed {
11889                    reindented_line.clear();
11890                    continue;
11891                }
11892                // Remaining spaces that didn't make a full tab stop
11893                if spaces_count > 0 {
11894                    reindented_line.extend(&space_cache[spaces_count - 1]);
11895                }
11896                // If we consume an extra character that was not indentation, add it back
11897                if let Some(extra_char) = first_non_indent_char {
11898                    reindented_line.push(extra_char);
11899                }
11900                // Append the rest of the line and replace old reference with new one
11901                reindented_line.extend(chars);
11902                *line = Cow::Owned(reindented_line.clone());
11903                reindented_line.clear();
11904            }
11905        });
11906    }
11907
11908    pub fn convert_to_upper_case(
11909        &mut self,
11910        _: &ConvertToUpperCase,
11911        window: &mut Window,
11912        cx: &mut Context<Self>,
11913    ) {
11914        self.manipulate_text(window, cx, |text| text.to_uppercase())
11915    }
11916
11917    pub fn convert_to_lower_case(
11918        &mut self,
11919        _: &ConvertToLowerCase,
11920        window: &mut Window,
11921        cx: &mut Context<Self>,
11922    ) {
11923        self.manipulate_text(window, cx, |text| text.to_lowercase())
11924    }
11925
11926    pub fn convert_to_title_case(
11927        &mut self,
11928        _: &ConvertToTitleCase,
11929        window: &mut Window,
11930        cx: &mut Context<Self>,
11931    ) {
11932        self.manipulate_text(window, cx, |text| {
11933            text.split('\n')
11934                .map(|line| line.to_case(Case::Title))
11935                .join("\n")
11936        })
11937    }
11938
11939    pub fn convert_to_snake_case(
11940        &mut self,
11941        _: &ConvertToSnakeCase,
11942        window: &mut Window,
11943        cx: &mut Context<Self>,
11944    ) {
11945        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11946    }
11947
11948    pub fn convert_to_kebab_case(
11949        &mut self,
11950        _: &ConvertToKebabCase,
11951        window: &mut Window,
11952        cx: &mut Context<Self>,
11953    ) {
11954        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11955    }
11956
11957    pub fn convert_to_upper_camel_case(
11958        &mut self,
11959        _: &ConvertToUpperCamelCase,
11960        window: &mut Window,
11961        cx: &mut Context<Self>,
11962    ) {
11963        self.manipulate_text(window, cx, |text| {
11964            text.split('\n')
11965                .map(|line| line.to_case(Case::UpperCamel))
11966                .join("\n")
11967        })
11968    }
11969
11970    pub fn convert_to_lower_camel_case(
11971        &mut self,
11972        _: &ConvertToLowerCamelCase,
11973        window: &mut Window,
11974        cx: &mut Context<Self>,
11975    ) {
11976        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11977    }
11978
11979    pub fn convert_to_opposite_case(
11980        &mut self,
11981        _: &ConvertToOppositeCase,
11982        window: &mut Window,
11983        cx: &mut Context<Self>,
11984    ) {
11985        self.manipulate_text(window, cx, |text| {
11986            text.chars()
11987                .fold(String::with_capacity(text.len()), |mut t, c| {
11988                    if c.is_uppercase() {
11989                        t.extend(c.to_lowercase());
11990                    } else {
11991                        t.extend(c.to_uppercase());
11992                    }
11993                    t
11994                })
11995        })
11996    }
11997
11998    pub fn convert_to_sentence_case(
11999        &mut self,
12000        _: &ConvertToSentenceCase,
12001        window: &mut Window,
12002        cx: &mut Context<Self>,
12003    ) {
12004        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12005    }
12006
12007    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12008        self.manipulate_text(window, cx, |text| {
12009            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12010            if has_upper_case_characters {
12011                text.to_lowercase()
12012            } else {
12013                text.to_uppercase()
12014            }
12015        })
12016    }
12017
12018    pub fn convert_to_rot13(
12019        &mut self,
12020        _: &ConvertToRot13,
12021        window: &mut Window,
12022        cx: &mut Context<Self>,
12023    ) {
12024        self.manipulate_text(window, cx, |text| {
12025            text.chars()
12026                .map(|c| match c {
12027                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12028                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12029                    _ => c,
12030                })
12031                .collect()
12032        })
12033    }
12034
12035    pub fn convert_to_rot47(
12036        &mut self,
12037        _: &ConvertToRot47,
12038        window: &mut Window,
12039        cx: &mut Context<Self>,
12040    ) {
12041        self.manipulate_text(window, cx, |text| {
12042            text.chars()
12043                .map(|c| {
12044                    let code_point = c as u32;
12045                    if code_point >= 33 && code_point <= 126 {
12046                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12047                    }
12048                    c
12049                })
12050                .collect()
12051        })
12052    }
12053
12054    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12055    where
12056        Fn: FnMut(&str) -> String,
12057    {
12058        let buffer = self.buffer.read(cx).snapshot(cx);
12059
12060        let mut new_selections = Vec::new();
12061        let mut edits = Vec::new();
12062        let mut selection_adjustment = 0isize;
12063
12064        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12065            let selection_is_empty = selection.is_empty();
12066
12067            let (start, end) = if selection_is_empty {
12068                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12069                (word_range.start, word_range.end)
12070            } else {
12071                (
12072                    buffer.point_to_offset(selection.start),
12073                    buffer.point_to_offset(selection.end),
12074                )
12075            };
12076
12077            let text = buffer.text_for_range(start..end).collect::<String>();
12078            let old_length = text.len() as isize;
12079            let text = callback(&text);
12080
12081            new_selections.push(Selection {
12082                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12083                end: MultiBufferOffset(
12084                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12085                ),
12086                goal: SelectionGoal::None,
12087                id: selection.id,
12088                reversed: selection.reversed,
12089            });
12090
12091            selection_adjustment += old_length - text.len() as isize;
12092
12093            edits.push((start..end, text));
12094        }
12095
12096        self.transact(window, cx, |this, window, cx| {
12097            this.buffer.update(cx, |buffer, cx| {
12098                buffer.edit(edits, None, cx);
12099            });
12100
12101            this.change_selections(Default::default(), window, cx, |s| {
12102                s.select(new_selections);
12103            });
12104
12105            this.request_autoscroll(Autoscroll::fit(), cx);
12106        });
12107    }
12108
12109    pub fn move_selection_on_drop(
12110        &mut self,
12111        selection: &Selection<Anchor>,
12112        target: DisplayPoint,
12113        is_cut: bool,
12114        window: &mut Window,
12115        cx: &mut Context<Self>,
12116    ) {
12117        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12118        let buffer = display_map.buffer_snapshot();
12119        let mut edits = Vec::new();
12120        let insert_point = display_map
12121            .clip_point(target, Bias::Left)
12122            .to_point(&display_map);
12123        let text = buffer
12124            .text_for_range(selection.start..selection.end)
12125            .collect::<String>();
12126        if is_cut {
12127            edits.push(((selection.start..selection.end), String::new()));
12128        }
12129        let insert_anchor = buffer.anchor_before(insert_point);
12130        edits.push(((insert_anchor..insert_anchor), text));
12131        let last_edit_start = insert_anchor.bias_left(buffer);
12132        let last_edit_end = insert_anchor.bias_right(buffer);
12133        self.transact(window, cx, |this, window, cx| {
12134            this.buffer.update(cx, |buffer, cx| {
12135                buffer.edit(edits, None, cx);
12136            });
12137            this.change_selections(Default::default(), window, cx, |s| {
12138                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12139            });
12140        });
12141    }
12142
12143    pub fn clear_selection_drag_state(&mut self) {
12144        self.selection_drag_state = SelectionDragState::None;
12145    }
12146
12147    pub fn duplicate(
12148        &mut self,
12149        upwards: bool,
12150        whole_lines: bool,
12151        window: &mut Window,
12152        cx: &mut Context<Self>,
12153    ) {
12154        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12155
12156        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12157        let buffer = display_map.buffer_snapshot();
12158        let selections = self.selections.all::<Point>(&display_map);
12159
12160        let mut edits = Vec::new();
12161        let mut selections_iter = selections.iter().peekable();
12162        while let Some(selection) = selections_iter.next() {
12163            let mut rows = selection.spanned_rows(false, &display_map);
12164            // duplicate line-wise
12165            if whole_lines || selection.start == selection.end {
12166                // Avoid duplicating the same lines twice.
12167                while let Some(next_selection) = selections_iter.peek() {
12168                    let next_rows = next_selection.spanned_rows(false, &display_map);
12169                    if next_rows.start < rows.end {
12170                        rows.end = next_rows.end;
12171                        selections_iter.next().unwrap();
12172                    } else {
12173                        break;
12174                    }
12175                }
12176
12177                // Copy the text from the selected row region and splice it either at the start
12178                // or end of the region.
12179                let start = Point::new(rows.start.0, 0);
12180                let end = Point::new(
12181                    rows.end.previous_row().0,
12182                    buffer.line_len(rows.end.previous_row()),
12183                );
12184
12185                let mut text = buffer.text_for_range(start..end).collect::<String>();
12186
12187                let insert_location = if upwards {
12188                    // When duplicating upward, we need to insert before the current line.
12189                    // If we're on the last line and it doesn't end with a newline,
12190                    // we need to add a newline before the duplicated content.
12191                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12192                        && buffer.max_point().column > 0
12193                        && !text.ends_with('\n');
12194
12195                    if needs_leading_newline {
12196                        text.insert(0, '\n');
12197                        end
12198                    } else {
12199                        text.push('\n');
12200                        Point::new(rows.start.0, 0)
12201                    }
12202                } else {
12203                    text.push('\n');
12204                    start
12205                };
12206                edits.push((insert_location..insert_location, text));
12207            } else {
12208                // duplicate character-wise
12209                let start = selection.start;
12210                let end = selection.end;
12211                let text = buffer.text_for_range(start..end).collect::<String>();
12212                edits.push((selection.end..selection.end, text));
12213            }
12214        }
12215
12216        self.transact(window, cx, |this, window, cx| {
12217            this.buffer.update(cx, |buffer, cx| {
12218                buffer.edit(edits, None, cx);
12219            });
12220
12221            // When duplicating upward with whole lines, move the cursor to the duplicated line
12222            if upwards && whole_lines {
12223                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12224
12225                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12226                    let mut new_ranges = Vec::new();
12227                    let selections = s.all::<Point>(&display_map);
12228                    let mut selections_iter = selections.iter().peekable();
12229
12230                    while let Some(first_selection) = selections_iter.next() {
12231                        // Group contiguous selections together to find the total row span
12232                        let mut group_selections = vec![first_selection];
12233                        let mut rows = first_selection.spanned_rows(false, &display_map);
12234
12235                        while let Some(next_selection) = selections_iter.peek() {
12236                            let next_rows = next_selection.spanned_rows(false, &display_map);
12237                            if next_rows.start < rows.end {
12238                                rows.end = next_rows.end;
12239                                group_selections.push(selections_iter.next().unwrap());
12240                            } else {
12241                                break;
12242                            }
12243                        }
12244
12245                        let row_count = rows.end.0 - rows.start.0;
12246
12247                        // Move all selections in this group up by the total number of duplicated rows
12248                        for selection in group_selections {
12249                            let new_start = Point::new(
12250                                selection.start.row.saturating_sub(row_count),
12251                                selection.start.column,
12252                            );
12253
12254                            let new_end = Point::new(
12255                                selection.end.row.saturating_sub(row_count),
12256                                selection.end.column,
12257                            );
12258
12259                            new_ranges.push(new_start..new_end);
12260                        }
12261                    }
12262
12263                    s.select_ranges(new_ranges);
12264                });
12265            }
12266
12267            this.request_autoscroll(Autoscroll::fit(), cx);
12268        });
12269    }
12270
12271    pub fn duplicate_line_up(
12272        &mut self,
12273        _: &DuplicateLineUp,
12274        window: &mut Window,
12275        cx: &mut Context<Self>,
12276    ) {
12277        self.duplicate(true, true, window, cx);
12278    }
12279
12280    pub fn duplicate_line_down(
12281        &mut self,
12282        _: &DuplicateLineDown,
12283        window: &mut Window,
12284        cx: &mut Context<Self>,
12285    ) {
12286        self.duplicate(false, true, window, cx);
12287    }
12288
12289    pub fn duplicate_selection(
12290        &mut self,
12291        _: &DuplicateSelection,
12292        window: &mut Window,
12293        cx: &mut Context<Self>,
12294    ) {
12295        self.duplicate(false, false, window, cx);
12296    }
12297
12298    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12299        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12300        if self.mode.is_single_line() {
12301            cx.propagate();
12302            return;
12303        }
12304
12305        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12306        let buffer = self.buffer.read(cx).snapshot(cx);
12307
12308        let mut edits = Vec::new();
12309        let mut unfold_ranges = Vec::new();
12310        let mut refold_creases = Vec::new();
12311
12312        let selections = self.selections.all::<Point>(&display_map);
12313        let mut selections = selections.iter().peekable();
12314        let mut contiguous_row_selections = Vec::new();
12315        let mut new_selections = Vec::new();
12316
12317        while let Some(selection) = selections.next() {
12318            // Find all the selections that span a contiguous row range
12319            let (start_row, end_row) = consume_contiguous_rows(
12320                &mut contiguous_row_selections,
12321                selection,
12322                &display_map,
12323                &mut selections,
12324            );
12325
12326            // Move the text spanned by the row range to be before the line preceding the row range
12327            if start_row.0 > 0 {
12328                let range_to_move = Point::new(
12329                    start_row.previous_row().0,
12330                    buffer.line_len(start_row.previous_row()),
12331                )
12332                    ..Point::new(
12333                        end_row.previous_row().0,
12334                        buffer.line_len(end_row.previous_row()),
12335                    );
12336                let insertion_point = display_map
12337                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12338                    .0;
12339
12340                // Don't move lines across excerpts
12341                if buffer
12342                    .excerpt_containing(insertion_point..range_to_move.end)
12343                    .is_some()
12344                {
12345                    let text = buffer
12346                        .text_for_range(range_to_move.clone())
12347                        .flat_map(|s| s.chars())
12348                        .skip(1)
12349                        .chain(['\n'])
12350                        .collect::<String>();
12351
12352                    edits.push((
12353                        buffer.anchor_after(range_to_move.start)
12354                            ..buffer.anchor_before(range_to_move.end),
12355                        String::new(),
12356                    ));
12357                    let insertion_anchor = buffer.anchor_after(insertion_point);
12358                    edits.push((insertion_anchor..insertion_anchor, text));
12359
12360                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12361
12362                    // Move selections up
12363                    new_selections.extend(contiguous_row_selections.drain(..).map(
12364                        |mut selection| {
12365                            selection.start.row -= row_delta;
12366                            selection.end.row -= row_delta;
12367                            selection
12368                        },
12369                    ));
12370
12371                    // Move folds up
12372                    unfold_ranges.push(range_to_move.clone());
12373                    for fold in display_map.folds_in_range(
12374                        buffer.anchor_before(range_to_move.start)
12375                            ..buffer.anchor_after(range_to_move.end),
12376                    ) {
12377                        let mut start = fold.range.start.to_point(&buffer);
12378                        let mut end = fold.range.end.to_point(&buffer);
12379                        start.row -= row_delta;
12380                        end.row -= row_delta;
12381                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12382                    }
12383                }
12384            }
12385
12386            // If we didn't move line(s), preserve the existing selections
12387            new_selections.append(&mut contiguous_row_selections);
12388        }
12389
12390        self.transact(window, cx, |this, window, cx| {
12391            this.unfold_ranges(&unfold_ranges, true, true, cx);
12392            this.buffer.update(cx, |buffer, cx| {
12393                for (range, text) in edits {
12394                    buffer.edit([(range, text)], None, cx);
12395                }
12396            });
12397            this.fold_creases(refold_creases, true, window, cx);
12398            this.change_selections(Default::default(), window, cx, |s| {
12399                s.select(new_selections);
12400            })
12401        });
12402    }
12403
12404    pub fn move_line_down(
12405        &mut self,
12406        _: &MoveLineDown,
12407        window: &mut Window,
12408        cx: &mut Context<Self>,
12409    ) {
12410        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12411        if self.mode.is_single_line() {
12412            cx.propagate();
12413            return;
12414        }
12415
12416        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12417        let buffer = self.buffer.read(cx).snapshot(cx);
12418
12419        let mut edits = Vec::new();
12420        let mut unfold_ranges = Vec::new();
12421        let mut refold_creases = Vec::new();
12422
12423        let selections = self.selections.all::<Point>(&display_map);
12424        let mut selections = selections.iter().peekable();
12425        let mut contiguous_row_selections = Vec::new();
12426        let mut new_selections = Vec::new();
12427
12428        while let Some(selection) = selections.next() {
12429            // Find all the selections that span a contiguous row range
12430            let (start_row, end_row) = consume_contiguous_rows(
12431                &mut contiguous_row_selections,
12432                selection,
12433                &display_map,
12434                &mut selections,
12435            );
12436
12437            // Move the text spanned by the row range to be after the last line of the row range
12438            if end_row.0 <= buffer.max_point().row {
12439                let range_to_move =
12440                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12441                let insertion_point = display_map
12442                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12443                    .0;
12444
12445                // Don't move lines across excerpt boundaries
12446                if buffer
12447                    .excerpt_containing(range_to_move.start..insertion_point)
12448                    .is_some()
12449                {
12450                    let mut text = String::from("\n");
12451                    text.extend(buffer.text_for_range(range_to_move.clone()));
12452                    text.pop(); // Drop trailing newline
12453                    edits.push((
12454                        buffer.anchor_after(range_to_move.start)
12455                            ..buffer.anchor_before(range_to_move.end),
12456                        String::new(),
12457                    ));
12458                    let insertion_anchor = buffer.anchor_after(insertion_point);
12459                    edits.push((insertion_anchor..insertion_anchor, text));
12460
12461                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12462
12463                    // Move selections down
12464                    new_selections.extend(contiguous_row_selections.drain(..).map(
12465                        |mut selection| {
12466                            selection.start.row += row_delta;
12467                            selection.end.row += row_delta;
12468                            selection
12469                        },
12470                    ));
12471
12472                    // Move folds down
12473                    unfold_ranges.push(range_to_move.clone());
12474                    for fold in display_map.folds_in_range(
12475                        buffer.anchor_before(range_to_move.start)
12476                            ..buffer.anchor_after(range_to_move.end),
12477                    ) {
12478                        let mut start = fold.range.start.to_point(&buffer);
12479                        let mut end = fold.range.end.to_point(&buffer);
12480                        start.row += row_delta;
12481                        end.row += row_delta;
12482                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12483                    }
12484                }
12485            }
12486
12487            // If we didn't move line(s), preserve the existing selections
12488            new_selections.append(&mut contiguous_row_selections);
12489        }
12490
12491        self.transact(window, cx, |this, window, cx| {
12492            this.unfold_ranges(&unfold_ranges, true, true, cx);
12493            this.buffer.update(cx, |buffer, cx| {
12494                for (range, text) in edits {
12495                    buffer.edit([(range, text)], None, cx);
12496                }
12497            });
12498            this.fold_creases(refold_creases, true, window, cx);
12499            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12500        });
12501    }
12502
12503    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12504        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12505        let text_layout_details = &self.text_layout_details(window);
12506        self.transact(window, cx, |this, window, cx| {
12507            let edits = this.change_selections(Default::default(), window, cx, |s| {
12508                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12509                s.move_with(|display_map, selection| {
12510                    if !selection.is_empty() {
12511                        return;
12512                    }
12513
12514                    let mut head = selection.head();
12515                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12516                    if head.column() == display_map.line_len(head.row()) {
12517                        transpose_offset = display_map
12518                            .buffer_snapshot()
12519                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12520                    }
12521
12522                    if transpose_offset == MultiBufferOffset(0) {
12523                        return;
12524                    }
12525
12526                    *head.column_mut() += 1;
12527                    head = display_map.clip_point(head, Bias::Right);
12528                    let goal = SelectionGoal::HorizontalPosition(
12529                        display_map
12530                            .x_for_display_point(head, text_layout_details)
12531                            .into(),
12532                    );
12533                    selection.collapse_to(head, goal);
12534
12535                    let transpose_start = display_map
12536                        .buffer_snapshot()
12537                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12538                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12539                        let transpose_end = display_map
12540                            .buffer_snapshot()
12541                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12542                        if let Some(ch) = display_map
12543                            .buffer_snapshot()
12544                            .chars_at(transpose_start)
12545                            .next()
12546                        {
12547                            edits.push((transpose_start..transpose_offset, String::new()));
12548                            edits.push((transpose_end..transpose_end, ch.to_string()));
12549                        }
12550                    }
12551                });
12552                edits
12553            });
12554            this.buffer
12555                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12556            let selections = this
12557                .selections
12558                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12559            this.change_selections(Default::default(), window, cx, |s| {
12560                s.select(selections);
12561            });
12562        });
12563    }
12564
12565    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12566        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12567        if self.mode.is_single_line() {
12568            cx.propagate();
12569            return;
12570        }
12571
12572        self.rewrap_impl(RewrapOptions::default(), cx)
12573    }
12574
12575    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12576        let buffer = self.buffer.read(cx).snapshot(cx);
12577        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12578
12579        #[derive(Clone, Debug, PartialEq)]
12580        enum CommentFormat {
12581            /// single line comment, with prefix for line
12582            Line(String),
12583            /// single line within a block comment, with prefix for line
12584            BlockLine(String),
12585            /// a single line of a block comment that includes the initial delimiter
12586            BlockCommentWithStart(BlockCommentConfig),
12587            /// a single line of a block comment that includes the ending delimiter
12588            BlockCommentWithEnd(BlockCommentConfig),
12589        }
12590
12591        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12592        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12593            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12594                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12595                .peekable();
12596
12597            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12598                row
12599            } else {
12600                return Vec::new();
12601            };
12602
12603            let language_settings = buffer.language_settings_at(selection.head(), cx);
12604            let language_scope = buffer.language_scope_at(selection.head());
12605
12606            let indent_and_prefix_for_row =
12607                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12608                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12609                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12610                        &language_scope
12611                    {
12612                        let indent_end = Point::new(row, indent.len);
12613                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12614                        let line_text_after_indent = buffer
12615                            .text_for_range(indent_end..line_end)
12616                            .collect::<String>();
12617
12618                        let is_within_comment_override = buffer
12619                            .language_scope_at(indent_end)
12620                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12621                        let comment_delimiters = if is_within_comment_override {
12622                            // we are within a comment syntax node, but we don't
12623                            // yet know what kind of comment: block, doc or line
12624                            match (
12625                                language_scope.documentation_comment(),
12626                                language_scope.block_comment(),
12627                            ) {
12628                                (Some(config), _) | (_, Some(config))
12629                                    if buffer.contains_str_at(indent_end, &config.start) =>
12630                                {
12631                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12632                                }
12633                                (Some(config), _) | (_, Some(config))
12634                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12635                                {
12636                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12637                                }
12638                                (Some(config), _) | (_, Some(config))
12639                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12640                                {
12641                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12642                                }
12643                                (_, _) => language_scope
12644                                    .line_comment_prefixes()
12645                                    .iter()
12646                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12647                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12648                            }
12649                        } else {
12650                            // we not in an overridden comment node, but we may
12651                            // be within a non-overridden line comment node
12652                            language_scope
12653                                .line_comment_prefixes()
12654                                .iter()
12655                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12656                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12657                        };
12658
12659                        let rewrap_prefix = language_scope
12660                            .rewrap_prefixes()
12661                            .iter()
12662                            .find_map(|prefix_regex| {
12663                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12664                                    if mat.start() == 0 {
12665                                        Some(mat.as_str().to_string())
12666                                    } else {
12667                                        None
12668                                    }
12669                                })
12670                            })
12671                            .flatten();
12672                        (comment_delimiters, rewrap_prefix)
12673                    } else {
12674                        (None, None)
12675                    };
12676                    (indent, comment_prefix, rewrap_prefix)
12677                };
12678
12679            let mut ranges = Vec::new();
12680            let from_empty_selection = selection.is_empty();
12681
12682            let mut current_range_start = first_row;
12683            let mut prev_row = first_row;
12684            let (
12685                mut current_range_indent,
12686                mut current_range_comment_delimiters,
12687                mut current_range_rewrap_prefix,
12688            ) = indent_and_prefix_for_row(first_row);
12689
12690            for row in non_blank_rows_iter.skip(1) {
12691                let has_paragraph_break = row > prev_row + 1;
12692
12693                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12694                    indent_and_prefix_for_row(row);
12695
12696                let has_indent_change = row_indent != current_range_indent;
12697                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12698
12699                let has_boundary_change = has_comment_change
12700                    || row_rewrap_prefix.is_some()
12701                    || (has_indent_change && current_range_comment_delimiters.is_some());
12702
12703                if has_paragraph_break || has_boundary_change {
12704                    ranges.push((
12705                        language_settings.clone(),
12706                        Point::new(current_range_start, 0)
12707                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12708                        current_range_indent,
12709                        current_range_comment_delimiters.clone(),
12710                        current_range_rewrap_prefix.clone(),
12711                        from_empty_selection,
12712                    ));
12713                    current_range_start = row;
12714                    current_range_indent = row_indent;
12715                    current_range_comment_delimiters = row_comment_delimiters;
12716                    current_range_rewrap_prefix = row_rewrap_prefix;
12717                }
12718                prev_row = row;
12719            }
12720
12721            ranges.push((
12722                language_settings.clone(),
12723                Point::new(current_range_start, 0)
12724                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12725                current_range_indent,
12726                current_range_comment_delimiters,
12727                current_range_rewrap_prefix,
12728                from_empty_selection,
12729            ));
12730
12731            ranges
12732        });
12733
12734        let mut edits = Vec::new();
12735        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12736
12737        for (
12738            language_settings,
12739            wrap_range,
12740            mut indent_size,
12741            comment_prefix,
12742            rewrap_prefix,
12743            from_empty_selection,
12744        ) in wrap_ranges
12745        {
12746            let mut start_row = wrap_range.start.row;
12747            let mut end_row = wrap_range.end.row;
12748
12749            // Skip selections that overlap with a range that has already been rewrapped.
12750            let selection_range = start_row..end_row;
12751            if rewrapped_row_ranges
12752                .iter()
12753                .any(|range| range.overlaps(&selection_range))
12754            {
12755                continue;
12756            }
12757
12758            let tab_size = language_settings.tab_size;
12759
12760            let (line_prefix, inside_comment) = match &comment_prefix {
12761                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12762                    (Some(prefix.as_str()), true)
12763                }
12764                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12765                    (Some(prefix.as_ref()), true)
12766                }
12767                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12768                    start: _,
12769                    end: _,
12770                    prefix,
12771                    tab_size,
12772                })) => {
12773                    indent_size.len += tab_size;
12774                    (Some(prefix.as_ref()), true)
12775                }
12776                None => (None, false),
12777            };
12778            let indent_prefix = indent_size.chars().collect::<String>();
12779            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12780
12781            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12782                RewrapBehavior::InComments => inside_comment,
12783                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12784                RewrapBehavior::Anywhere => true,
12785            };
12786
12787            let should_rewrap = options.override_language_settings
12788                || allow_rewrap_based_on_language
12789                || self.hard_wrap.is_some();
12790            if !should_rewrap {
12791                continue;
12792            }
12793
12794            if from_empty_selection {
12795                'expand_upwards: while start_row > 0 {
12796                    let prev_row = start_row - 1;
12797                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12798                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12799                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12800                    {
12801                        start_row = prev_row;
12802                    } else {
12803                        break 'expand_upwards;
12804                    }
12805                }
12806
12807                'expand_downwards: while end_row < buffer.max_point().row {
12808                    let next_row = end_row + 1;
12809                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12810                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12811                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12812                    {
12813                        end_row = next_row;
12814                    } else {
12815                        break 'expand_downwards;
12816                    }
12817                }
12818            }
12819
12820            let start = Point::new(start_row, 0);
12821            let start_offset = ToOffset::to_offset(&start, &buffer);
12822            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12823            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12824            let mut first_line_delimiter = None;
12825            let mut last_line_delimiter = None;
12826            let Some(lines_without_prefixes) = selection_text
12827                .lines()
12828                .enumerate()
12829                .map(|(ix, line)| {
12830                    let line_trimmed = line.trim_start();
12831                    if rewrap_prefix.is_some() && ix > 0 {
12832                        Ok(line_trimmed)
12833                    } else if let Some(
12834                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12835                            start,
12836                            prefix,
12837                            end,
12838                            tab_size,
12839                        })
12840                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12841                            start,
12842                            prefix,
12843                            end,
12844                            tab_size,
12845                        }),
12846                    ) = &comment_prefix
12847                    {
12848                        let line_trimmed = line_trimmed
12849                            .strip_prefix(start.as_ref())
12850                            .map(|s| {
12851                                let mut indent_size = indent_size;
12852                                indent_size.len -= tab_size;
12853                                let indent_prefix: String = indent_size.chars().collect();
12854                                first_line_delimiter = Some((indent_prefix, start));
12855                                s.trim_start()
12856                            })
12857                            .unwrap_or(line_trimmed);
12858                        let line_trimmed = line_trimmed
12859                            .strip_suffix(end.as_ref())
12860                            .map(|s| {
12861                                last_line_delimiter = Some(end);
12862                                s.trim_end()
12863                            })
12864                            .unwrap_or(line_trimmed);
12865                        let line_trimmed = line_trimmed
12866                            .strip_prefix(prefix.as_ref())
12867                            .unwrap_or(line_trimmed);
12868                        Ok(line_trimmed)
12869                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12870                        line_trimmed.strip_prefix(prefix).with_context(|| {
12871                            format!("line did not start with prefix {prefix:?}: {line:?}")
12872                        })
12873                    } else {
12874                        line_trimmed
12875                            .strip_prefix(&line_prefix.trim_start())
12876                            .with_context(|| {
12877                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12878                            })
12879                    }
12880                })
12881                .collect::<Result<Vec<_>, _>>()
12882                .log_err()
12883            else {
12884                continue;
12885            };
12886
12887            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12888                buffer
12889                    .language_settings_at(Point::new(start_row, 0), cx)
12890                    .preferred_line_length as usize
12891            });
12892
12893            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12894                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12895            } else {
12896                line_prefix.clone()
12897            };
12898
12899            let wrapped_text = {
12900                let mut wrapped_text = wrap_with_prefix(
12901                    line_prefix,
12902                    subsequent_lines_prefix,
12903                    lines_without_prefixes.join("\n"),
12904                    wrap_column,
12905                    tab_size,
12906                    options.preserve_existing_whitespace,
12907                );
12908
12909                if let Some((indent, delimiter)) = first_line_delimiter {
12910                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12911                }
12912                if let Some(last_line) = last_line_delimiter {
12913                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12914                }
12915
12916                wrapped_text
12917            };
12918
12919            // TODO: should always use char-based diff while still supporting cursor behavior that
12920            // matches vim.
12921            let mut diff_options = DiffOptions::default();
12922            if options.override_language_settings {
12923                diff_options.max_word_diff_len = 0;
12924                diff_options.max_word_diff_line_count = 0;
12925            } else {
12926                diff_options.max_word_diff_len = usize::MAX;
12927                diff_options.max_word_diff_line_count = usize::MAX;
12928            }
12929
12930            for (old_range, new_text) in
12931                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12932            {
12933                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12934                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12935                edits.push((edit_start..edit_end, new_text));
12936            }
12937
12938            rewrapped_row_ranges.push(start_row..=end_row);
12939        }
12940
12941        self.buffer
12942            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12943    }
12944
12945    pub fn cut_common(
12946        &mut self,
12947        cut_no_selection_line: bool,
12948        window: &mut Window,
12949        cx: &mut Context<Self>,
12950    ) -> ClipboardItem {
12951        let mut text = String::new();
12952        let buffer = self.buffer.read(cx).snapshot(cx);
12953        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12954        let mut clipboard_selections = Vec::with_capacity(selections.len());
12955        {
12956            let max_point = buffer.max_point();
12957            let mut is_first = true;
12958            let mut prev_selection_was_entire_line = false;
12959            for selection in &mut selections {
12960                let is_entire_line =
12961                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12962                if is_entire_line {
12963                    selection.start = Point::new(selection.start.row, 0);
12964                    if !selection.is_empty() && selection.end.column == 0 {
12965                        selection.end = cmp::min(max_point, selection.end);
12966                    } else {
12967                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12968                    }
12969                    selection.goal = SelectionGoal::None;
12970                }
12971                if is_first {
12972                    is_first = false;
12973                } else if !prev_selection_was_entire_line {
12974                    text += "\n";
12975                }
12976                prev_selection_was_entire_line = is_entire_line;
12977                let mut len = 0;
12978                for chunk in buffer.text_for_range(selection.start..selection.end) {
12979                    text.push_str(chunk);
12980                    len += chunk.len();
12981                }
12982
12983                clipboard_selections.push(ClipboardSelection::for_buffer(
12984                    len,
12985                    is_entire_line,
12986                    selection.range(),
12987                    &buffer,
12988                    self.project.as_ref(),
12989                    cx,
12990                ));
12991            }
12992        }
12993
12994        self.transact(window, cx, |this, window, cx| {
12995            this.change_selections(Default::default(), window, cx, |s| {
12996                s.select(selections);
12997            });
12998            this.insert("", window, cx);
12999        });
13000        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13001    }
13002
13003    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13004        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13005        let item = self.cut_common(true, window, cx);
13006        cx.write_to_clipboard(item);
13007    }
13008
13009    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13010        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13011        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13012            s.move_with(|snapshot, sel| {
13013                if sel.is_empty() {
13014                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13015                }
13016                if sel.is_empty() {
13017                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13018                }
13019            });
13020        });
13021        let item = self.cut_common(false, window, cx);
13022        cx.set_global(KillRing(item))
13023    }
13024
13025    pub fn kill_ring_yank(
13026        &mut self,
13027        _: &KillRingYank,
13028        window: &mut Window,
13029        cx: &mut Context<Self>,
13030    ) {
13031        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13032        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13033            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13034                (kill_ring.text().to_string(), kill_ring.metadata_json())
13035            } else {
13036                return;
13037            }
13038        } else {
13039            return;
13040        };
13041        self.do_paste(&text, metadata, false, window, cx);
13042    }
13043
13044    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13045        self.do_copy(true, cx);
13046    }
13047
13048    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13049        self.do_copy(false, cx);
13050    }
13051
13052    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13053        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13054        let buffer = self.buffer.read(cx).read(cx);
13055        let mut text = String::new();
13056
13057        let mut clipboard_selections = Vec::with_capacity(selections.len());
13058        {
13059            let max_point = buffer.max_point();
13060            let mut is_first = true;
13061            let mut prev_selection_was_entire_line = false;
13062            for selection in &selections {
13063                let mut start = selection.start;
13064                let mut end = selection.end;
13065                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13066                let mut add_trailing_newline = false;
13067                if is_entire_line {
13068                    start = Point::new(start.row, 0);
13069                    let next_line_start = Point::new(end.row + 1, 0);
13070                    if next_line_start <= max_point {
13071                        end = next_line_start;
13072                    } else {
13073                        // We're on the last line without a trailing newline.
13074                        // Copy to the end of the line and add a newline afterwards.
13075                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13076                        add_trailing_newline = true;
13077                    }
13078                }
13079
13080                let mut trimmed_selections = Vec::new();
13081                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13082                    let row = MultiBufferRow(start.row);
13083                    let first_indent = buffer.indent_size_for_line(row);
13084                    if first_indent.len == 0 || start.column > first_indent.len {
13085                        trimmed_selections.push(start..end);
13086                    } else {
13087                        trimmed_selections.push(
13088                            Point::new(row.0, first_indent.len)
13089                                ..Point::new(row.0, buffer.line_len(row)),
13090                        );
13091                        for row in start.row + 1..=end.row {
13092                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13093                            if row == end.row {
13094                                line_len = end.column;
13095                            }
13096                            if line_len == 0 {
13097                                trimmed_selections
13098                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13099                                continue;
13100                            }
13101                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13102                            if row_indent_size.len >= first_indent.len {
13103                                trimmed_selections.push(
13104                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13105                                );
13106                            } else {
13107                                trimmed_selections.clear();
13108                                trimmed_selections.push(start..end);
13109                                break;
13110                            }
13111                        }
13112                    }
13113                } else {
13114                    trimmed_selections.push(start..end);
13115                }
13116
13117                for trimmed_range in trimmed_selections {
13118                    if is_first {
13119                        is_first = false;
13120                    } else if !prev_selection_was_entire_line {
13121                        text += "\n";
13122                    }
13123                    prev_selection_was_entire_line = is_entire_line;
13124                    let mut len = 0;
13125                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13126                        text.push_str(chunk);
13127                        len += chunk.len();
13128                    }
13129                    if add_trailing_newline {
13130                        text.push('\n');
13131                        len += 1;
13132                    }
13133                    clipboard_selections.push(ClipboardSelection::for_buffer(
13134                        len,
13135                        is_entire_line,
13136                        trimmed_range,
13137                        &buffer,
13138                        self.project.as_ref(),
13139                        cx,
13140                    ));
13141                }
13142            }
13143        }
13144
13145        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13146            text,
13147            clipboard_selections,
13148        ));
13149    }
13150
13151    pub fn do_paste(
13152        &mut self,
13153        text: &String,
13154        clipboard_selections: Option<Vec<ClipboardSelection>>,
13155        handle_entire_lines: bool,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        if self.read_only(cx) {
13160            return;
13161        }
13162
13163        let clipboard_text = Cow::Borrowed(text.as_str());
13164
13165        self.transact(window, cx, |this, window, cx| {
13166            let had_active_edit_prediction = this.has_active_edit_prediction();
13167            let display_map = this.display_snapshot(cx);
13168            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13169            let cursor_offset = this
13170                .selections
13171                .last::<MultiBufferOffset>(&display_map)
13172                .head();
13173
13174            if let Some(mut clipboard_selections) = clipboard_selections {
13175                let all_selections_were_entire_line =
13176                    clipboard_selections.iter().all(|s| s.is_entire_line);
13177                let first_selection_indent_column =
13178                    clipboard_selections.first().map(|s| s.first_line_indent);
13179                if clipboard_selections.len() != old_selections.len() {
13180                    clipboard_selections.drain(..);
13181                }
13182                let mut auto_indent_on_paste = true;
13183
13184                this.buffer.update(cx, |buffer, cx| {
13185                    let snapshot = buffer.read(cx);
13186                    auto_indent_on_paste = snapshot
13187                        .language_settings_at(cursor_offset, cx)
13188                        .auto_indent_on_paste;
13189
13190                    let mut start_offset = 0;
13191                    let mut edits = Vec::new();
13192                    let mut original_indent_columns = Vec::new();
13193                    for (ix, selection) in old_selections.iter().enumerate() {
13194                        let to_insert;
13195                        let entire_line;
13196                        let original_indent_column;
13197                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13198                            let end_offset = start_offset + clipboard_selection.len;
13199                            to_insert = &clipboard_text[start_offset..end_offset];
13200                            entire_line = clipboard_selection.is_entire_line;
13201                            start_offset = if entire_line {
13202                                end_offset
13203                            } else {
13204                                end_offset + 1
13205                            };
13206                            original_indent_column = Some(clipboard_selection.first_line_indent);
13207                        } else {
13208                            to_insert = &*clipboard_text;
13209                            entire_line = all_selections_were_entire_line;
13210                            original_indent_column = first_selection_indent_column
13211                        }
13212
13213                        let (range, to_insert) =
13214                            if selection.is_empty() && handle_entire_lines && entire_line {
13215                                // If the corresponding selection was empty when this slice of the
13216                                // clipboard text was written, then the entire line containing the
13217                                // selection was copied. If this selection is also currently empty,
13218                                // then paste the line before the current line of the buffer.
13219                                let column = selection.start.to_point(&snapshot).column as usize;
13220                                let line_start = selection.start - column;
13221                                (line_start..line_start, Cow::Borrowed(to_insert))
13222                            } else {
13223                                let language = snapshot.language_at(selection.head());
13224                                let range = selection.range();
13225                                if let Some(language) = language
13226                                    && language.name() == "Markdown".into()
13227                                {
13228                                    edit_for_markdown_paste(
13229                                        &snapshot,
13230                                        range,
13231                                        to_insert,
13232                                        url::Url::parse(to_insert).ok(),
13233                                    )
13234                                } else {
13235                                    (range, Cow::Borrowed(to_insert))
13236                                }
13237                            };
13238
13239                        edits.push((range, to_insert));
13240                        original_indent_columns.push(original_indent_column);
13241                    }
13242                    drop(snapshot);
13243
13244                    buffer.edit(
13245                        edits,
13246                        if auto_indent_on_paste {
13247                            Some(AutoindentMode::Block {
13248                                original_indent_columns,
13249                            })
13250                        } else {
13251                            None
13252                        },
13253                        cx,
13254                    );
13255                });
13256
13257                let selections = this
13258                    .selections
13259                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13260                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13261            } else {
13262                let url = url::Url::parse(&clipboard_text).ok();
13263
13264                let auto_indent_mode = if !clipboard_text.is_empty() {
13265                    Some(AutoindentMode::Block {
13266                        original_indent_columns: Vec::new(),
13267                    })
13268                } else {
13269                    None
13270                };
13271
13272                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13273                    let snapshot = buffer.snapshot(cx);
13274
13275                    let anchors = old_selections
13276                        .iter()
13277                        .map(|s| {
13278                            let anchor = snapshot.anchor_after(s.head());
13279                            s.map(|_| anchor)
13280                        })
13281                        .collect::<Vec<_>>();
13282
13283                    let mut edits = Vec::new();
13284
13285                    for selection in old_selections.iter() {
13286                        let language = snapshot.language_at(selection.head());
13287                        let range = selection.range();
13288
13289                        let (edit_range, edit_text) = if let Some(language) = language
13290                            && language.name() == "Markdown".into()
13291                        {
13292                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13293                        } else {
13294                            (range, clipboard_text.clone())
13295                        };
13296
13297                        edits.push((edit_range, edit_text));
13298                    }
13299
13300                    drop(snapshot);
13301                    buffer.edit(edits, auto_indent_mode, cx);
13302
13303                    anchors
13304                });
13305
13306                this.change_selections(Default::default(), window, cx, |s| {
13307                    s.select_anchors(selection_anchors);
13308                });
13309            }
13310
13311            //   🤔                 |    ..     | show_in_menu |
13312            // | ..                  |   true        true
13313            // | had_edit_prediction |   false       true
13314
13315            let trigger_in_words =
13316                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13317
13318            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13319        });
13320    }
13321
13322    pub fn diff_clipboard_with_selection(
13323        &mut self,
13324        _: &DiffClipboardWithSelection,
13325        window: &mut Window,
13326        cx: &mut Context<Self>,
13327    ) {
13328        let selections = self
13329            .selections
13330            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13331
13332        if selections.is_empty() {
13333            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13334            return;
13335        };
13336
13337        let clipboard_text = match cx.read_from_clipboard() {
13338            Some(item) => match item.entries().first() {
13339                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13340                _ => None,
13341            },
13342            None => None,
13343        };
13344
13345        let Some(clipboard_text) = clipboard_text else {
13346            log::warn!("Clipboard doesn't contain text.");
13347            return;
13348        };
13349
13350        window.dispatch_action(
13351            Box::new(DiffClipboardWithSelectionData {
13352                clipboard_text,
13353                editor: cx.entity(),
13354            }),
13355            cx,
13356        );
13357    }
13358
13359    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13360        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13361        if let Some(item) = cx.read_from_clipboard() {
13362            let entries = item.entries();
13363
13364            match entries.first() {
13365                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13366                // of all the pasted entries.
13367                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13368                    .do_paste(
13369                        clipboard_string.text(),
13370                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13371                        true,
13372                        window,
13373                        cx,
13374                    ),
13375                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13376            }
13377        }
13378    }
13379
13380    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13381        if self.read_only(cx) {
13382            return;
13383        }
13384
13385        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13386
13387        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13388            if let Some((selections, _)) =
13389                self.selection_history.transaction(transaction_id).cloned()
13390            {
13391                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13392                    s.select_anchors(selections.to_vec());
13393                });
13394            } else {
13395                log::error!(
13396                    "No entry in selection_history found for undo. \
13397                     This may correspond to a bug where undo does not update the selection. \
13398                     If this is occurring, please add details to \
13399                     https://github.com/zed-industries/zed/issues/22692"
13400                );
13401            }
13402            self.request_autoscroll(Autoscroll::fit(), cx);
13403            self.unmark_text(window, cx);
13404            self.refresh_edit_prediction(true, false, window, cx);
13405            cx.emit(EditorEvent::Edited { transaction_id });
13406            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13407        }
13408    }
13409
13410    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13411        if self.read_only(cx) {
13412            return;
13413        }
13414
13415        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13416
13417        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13418            if let Some((_, Some(selections))) =
13419                self.selection_history.transaction(transaction_id).cloned()
13420            {
13421                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13422                    s.select_anchors(selections.to_vec());
13423                });
13424            } else {
13425                log::error!(
13426                    "No entry in selection_history found for redo. \
13427                     This may correspond to a bug where undo does not update the selection. \
13428                     If this is occurring, please add details to \
13429                     https://github.com/zed-industries/zed/issues/22692"
13430                );
13431            }
13432            self.request_autoscroll(Autoscroll::fit(), cx);
13433            self.unmark_text(window, cx);
13434            self.refresh_edit_prediction(true, false, window, cx);
13435            cx.emit(EditorEvent::Edited { transaction_id });
13436        }
13437    }
13438
13439    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13440        self.buffer
13441            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13442    }
13443
13444    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13445        self.buffer
13446            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13447    }
13448
13449    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13450        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13451        self.change_selections(Default::default(), window, cx, |s| {
13452            s.move_with(|map, selection| {
13453                let cursor = if selection.is_empty() {
13454                    movement::left(map, selection.start)
13455                } else {
13456                    selection.start
13457                };
13458                selection.collapse_to(cursor, SelectionGoal::None);
13459            });
13460        })
13461    }
13462
13463    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13464        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13465        self.change_selections(Default::default(), window, cx, |s| {
13466            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13467        })
13468    }
13469
13470    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13471        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13472        self.change_selections(Default::default(), window, cx, |s| {
13473            s.move_with(|map, selection| {
13474                let cursor = if selection.is_empty() {
13475                    movement::right(map, selection.end)
13476                } else {
13477                    selection.end
13478                };
13479                selection.collapse_to(cursor, SelectionGoal::None)
13480            });
13481        })
13482    }
13483
13484    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13485        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13486        self.change_selections(Default::default(), window, cx, |s| {
13487            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13488        });
13489    }
13490
13491    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13492        if self.take_rename(true, window, cx).is_some() {
13493            return;
13494        }
13495
13496        if self.mode.is_single_line() {
13497            cx.propagate();
13498            return;
13499        }
13500
13501        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13502
13503        let text_layout_details = &self.text_layout_details(window);
13504        let selection_count = self.selections.count();
13505        let first_selection = self.selections.first_anchor();
13506
13507        self.change_selections(Default::default(), window, cx, |s| {
13508            s.move_with(|map, selection| {
13509                if !selection.is_empty() {
13510                    selection.goal = SelectionGoal::None;
13511                }
13512                let (cursor, goal) = movement::up(
13513                    map,
13514                    selection.start,
13515                    selection.goal,
13516                    false,
13517                    text_layout_details,
13518                );
13519                selection.collapse_to(cursor, goal);
13520            });
13521        });
13522
13523        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13524        {
13525            cx.propagate();
13526        }
13527    }
13528
13529    pub fn move_up_by_lines(
13530        &mut self,
13531        action: &MoveUpByLines,
13532        window: &mut Window,
13533        cx: &mut Context<Self>,
13534    ) {
13535        if self.take_rename(true, window, cx).is_some() {
13536            return;
13537        }
13538
13539        if self.mode.is_single_line() {
13540            cx.propagate();
13541            return;
13542        }
13543
13544        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13545
13546        let text_layout_details = &self.text_layout_details(window);
13547
13548        self.change_selections(Default::default(), window, cx, |s| {
13549            s.move_with(|map, selection| {
13550                if !selection.is_empty() {
13551                    selection.goal = SelectionGoal::None;
13552                }
13553                let (cursor, goal) = movement::up_by_rows(
13554                    map,
13555                    selection.start,
13556                    action.lines,
13557                    selection.goal,
13558                    false,
13559                    text_layout_details,
13560                );
13561                selection.collapse_to(cursor, goal);
13562            });
13563        })
13564    }
13565
13566    pub fn move_down_by_lines(
13567        &mut self,
13568        action: &MoveDownByLines,
13569        window: &mut Window,
13570        cx: &mut Context<Self>,
13571    ) {
13572        if self.take_rename(true, window, cx).is_some() {
13573            return;
13574        }
13575
13576        if self.mode.is_single_line() {
13577            cx.propagate();
13578            return;
13579        }
13580
13581        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13582
13583        let text_layout_details = &self.text_layout_details(window);
13584
13585        self.change_selections(Default::default(), window, cx, |s| {
13586            s.move_with(|map, selection| {
13587                if !selection.is_empty() {
13588                    selection.goal = SelectionGoal::None;
13589                }
13590                let (cursor, goal) = movement::down_by_rows(
13591                    map,
13592                    selection.start,
13593                    action.lines,
13594                    selection.goal,
13595                    false,
13596                    text_layout_details,
13597                );
13598                selection.collapse_to(cursor, goal);
13599            });
13600        })
13601    }
13602
13603    pub fn select_down_by_lines(
13604        &mut self,
13605        action: &SelectDownByLines,
13606        window: &mut Window,
13607        cx: &mut Context<Self>,
13608    ) {
13609        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13610        let text_layout_details = &self.text_layout_details(window);
13611        self.change_selections(Default::default(), window, cx, |s| {
13612            s.move_heads_with(|map, head, goal| {
13613                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13614            })
13615        })
13616    }
13617
13618    pub fn select_up_by_lines(
13619        &mut self,
13620        action: &SelectUpByLines,
13621        window: &mut Window,
13622        cx: &mut Context<Self>,
13623    ) {
13624        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13625        let text_layout_details = &self.text_layout_details(window);
13626        self.change_selections(Default::default(), window, cx, |s| {
13627            s.move_heads_with(|map, head, goal| {
13628                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13629            })
13630        })
13631    }
13632
13633    pub fn select_page_up(
13634        &mut self,
13635        _: &SelectPageUp,
13636        window: &mut Window,
13637        cx: &mut Context<Self>,
13638    ) {
13639        let Some(row_count) = self.visible_row_count() else {
13640            return;
13641        };
13642
13643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13644
13645        let text_layout_details = &self.text_layout_details(window);
13646
13647        self.change_selections(Default::default(), window, cx, |s| {
13648            s.move_heads_with(|map, head, goal| {
13649                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13650            })
13651        })
13652    }
13653
13654    pub fn move_page_up(
13655        &mut self,
13656        action: &MovePageUp,
13657        window: &mut Window,
13658        cx: &mut Context<Self>,
13659    ) {
13660        if self.take_rename(true, window, cx).is_some() {
13661            return;
13662        }
13663
13664        if self
13665            .context_menu
13666            .borrow_mut()
13667            .as_mut()
13668            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13669            .unwrap_or(false)
13670        {
13671            return;
13672        }
13673
13674        if matches!(self.mode, EditorMode::SingleLine) {
13675            cx.propagate();
13676            return;
13677        }
13678
13679        let Some(row_count) = self.visible_row_count() else {
13680            return;
13681        };
13682
13683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13684
13685        let effects = if action.center_cursor {
13686            SelectionEffects::scroll(Autoscroll::center())
13687        } else {
13688            SelectionEffects::default()
13689        };
13690
13691        let text_layout_details = &self.text_layout_details(window);
13692
13693        self.change_selections(effects, window, cx, |s| {
13694            s.move_with(|map, selection| {
13695                if !selection.is_empty() {
13696                    selection.goal = SelectionGoal::None;
13697                }
13698                let (cursor, goal) = movement::up_by_rows(
13699                    map,
13700                    selection.end,
13701                    row_count,
13702                    selection.goal,
13703                    false,
13704                    text_layout_details,
13705                );
13706                selection.collapse_to(cursor, goal);
13707            });
13708        });
13709    }
13710
13711    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13712        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13713        let text_layout_details = &self.text_layout_details(window);
13714        self.change_selections(Default::default(), window, cx, |s| {
13715            s.move_heads_with(|map, head, goal| {
13716                movement::up(map, head, goal, false, text_layout_details)
13717            })
13718        })
13719    }
13720
13721    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13722        self.take_rename(true, window, cx);
13723
13724        if self.mode.is_single_line() {
13725            cx.propagate();
13726            return;
13727        }
13728
13729        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13730
13731        let text_layout_details = &self.text_layout_details(window);
13732        let selection_count = self.selections.count();
13733        let first_selection = self.selections.first_anchor();
13734
13735        self.change_selections(Default::default(), window, cx, |s| {
13736            s.move_with(|map, selection| {
13737                if !selection.is_empty() {
13738                    selection.goal = SelectionGoal::None;
13739                }
13740                let (cursor, goal) = movement::down(
13741                    map,
13742                    selection.end,
13743                    selection.goal,
13744                    false,
13745                    text_layout_details,
13746                );
13747                selection.collapse_to(cursor, goal);
13748            });
13749        });
13750
13751        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13752        {
13753            cx.propagate();
13754        }
13755    }
13756
13757    pub fn select_page_down(
13758        &mut self,
13759        _: &SelectPageDown,
13760        window: &mut Window,
13761        cx: &mut Context<Self>,
13762    ) {
13763        let Some(row_count) = self.visible_row_count() else {
13764            return;
13765        };
13766
13767        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13768
13769        let text_layout_details = &self.text_layout_details(window);
13770
13771        self.change_selections(Default::default(), window, cx, |s| {
13772            s.move_heads_with(|map, head, goal| {
13773                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13774            })
13775        })
13776    }
13777
13778    pub fn move_page_down(
13779        &mut self,
13780        action: &MovePageDown,
13781        window: &mut Window,
13782        cx: &mut Context<Self>,
13783    ) {
13784        if self.take_rename(true, window, cx).is_some() {
13785            return;
13786        }
13787
13788        if self
13789            .context_menu
13790            .borrow_mut()
13791            .as_mut()
13792            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13793            .unwrap_or(false)
13794        {
13795            return;
13796        }
13797
13798        if matches!(self.mode, EditorMode::SingleLine) {
13799            cx.propagate();
13800            return;
13801        }
13802
13803        let Some(row_count) = self.visible_row_count() else {
13804            return;
13805        };
13806
13807        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13808
13809        let effects = if action.center_cursor {
13810            SelectionEffects::scroll(Autoscroll::center())
13811        } else {
13812            SelectionEffects::default()
13813        };
13814
13815        let text_layout_details = &self.text_layout_details(window);
13816        self.change_selections(effects, window, cx, |s| {
13817            s.move_with(|map, selection| {
13818                if !selection.is_empty() {
13819                    selection.goal = SelectionGoal::None;
13820                }
13821                let (cursor, goal) = movement::down_by_rows(
13822                    map,
13823                    selection.end,
13824                    row_count,
13825                    selection.goal,
13826                    false,
13827                    text_layout_details,
13828                );
13829                selection.collapse_to(cursor, goal);
13830            });
13831        });
13832    }
13833
13834    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13835        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13836        let text_layout_details = &self.text_layout_details(window);
13837        self.change_selections(Default::default(), window, cx, |s| {
13838            s.move_heads_with(|map, head, goal| {
13839                movement::down(map, head, goal, false, text_layout_details)
13840            })
13841        });
13842    }
13843
13844    pub fn context_menu_first(
13845        &mut self,
13846        _: &ContextMenuFirst,
13847        window: &mut Window,
13848        cx: &mut Context<Self>,
13849    ) {
13850        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13851            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13852        }
13853    }
13854
13855    pub fn context_menu_prev(
13856        &mut self,
13857        _: &ContextMenuPrevious,
13858        window: &mut Window,
13859        cx: &mut Context<Self>,
13860    ) {
13861        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13862            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13863        }
13864    }
13865
13866    pub fn context_menu_next(
13867        &mut self,
13868        _: &ContextMenuNext,
13869        window: &mut Window,
13870        cx: &mut Context<Self>,
13871    ) {
13872        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13873            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13874        }
13875    }
13876
13877    pub fn context_menu_last(
13878        &mut self,
13879        _: &ContextMenuLast,
13880        window: &mut Window,
13881        cx: &mut Context<Self>,
13882    ) {
13883        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13884            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13885        }
13886    }
13887
13888    pub fn signature_help_prev(
13889        &mut self,
13890        _: &SignatureHelpPrevious,
13891        _: &mut Window,
13892        cx: &mut Context<Self>,
13893    ) {
13894        if let Some(popover) = self.signature_help_state.popover_mut() {
13895            if popover.current_signature == 0 {
13896                popover.current_signature = popover.signatures.len() - 1;
13897            } else {
13898                popover.current_signature -= 1;
13899            }
13900            cx.notify();
13901        }
13902    }
13903
13904    pub fn signature_help_next(
13905        &mut self,
13906        _: &SignatureHelpNext,
13907        _: &mut Window,
13908        cx: &mut Context<Self>,
13909    ) {
13910        if let Some(popover) = self.signature_help_state.popover_mut() {
13911            if popover.current_signature + 1 == popover.signatures.len() {
13912                popover.current_signature = 0;
13913            } else {
13914                popover.current_signature += 1;
13915            }
13916            cx.notify();
13917        }
13918    }
13919
13920    pub fn move_to_previous_word_start(
13921        &mut self,
13922        _: &MoveToPreviousWordStart,
13923        window: &mut Window,
13924        cx: &mut Context<Self>,
13925    ) {
13926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13927        self.change_selections(Default::default(), window, cx, |s| {
13928            s.move_cursors_with(|map, head, _| {
13929                (
13930                    movement::previous_word_start(map, head),
13931                    SelectionGoal::None,
13932                )
13933            });
13934        })
13935    }
13936
13937    pub fn move_to_previous_subword_start(
13938        &mut self,
13939        _: &MoveToPreviousSubwordStart,
13940        window: &mut Window,
13941        cx: &mut Context<Self>,
13942    ) {
13943        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13944        self.change_selections(Default::default(), window, cx, |s| {
13945            s.move_cursors_with(|map, head, _| {
13946                (
13947                    movement::previous_subword_start(map, head),
13948                    SelectionGoal::None,
13949                )
13950            });
13951        })
13952    }
13953
13954    pub fn select_to_previous_word_start(
13955        &mut self,
13956        _: &SelectToPreviousWordStart,
13957        window: &mut Window,
13958        cx: &mut Context<Self>,
13959    ) {
13960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13961        self.change_selections(Default::default(), window, cx, |s| {
13962            s.move_heads_with(|map, head, _| {
13963                (
13964                    movement::previous_word_start(map, head),
13965                    SelectionGoal::None,
13966                )
13967            });
13968        })
13969    }
13970
13971    pub fn select_to_previous_subword_start(
13972        &mut self,
13973        _: &SelectToPreviousSubwordStart,
13974        window: &mut Window,
13975        cx: &mut Context<Self>,
13976    ) {
13977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13978        self.change_selections(Default::default(), window, cx, |s| {
13979            s.move_heads_with(|map, head, _| {
13980                (
13981                    movement::previous_subword_start(map, head),
13982                    SelectionGoal::None,
13983                )
13984            });
13985        })
13986    }
13987
13988    pub fn delete_to_previous_word_start(
13989        &mut self,
13990        action: &DeleteToPreviousWordStart,
13991        window: &mut Window,
13992        cx: &mut Context<Self>,
13993    ) {
13994        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13995        self.transact(window, cx, |this, window, cx| {
13996            this.select_autoclose_pair(window, cx);
13997            this.change_selections(Default::default(), window, cx, |s| {
13998                s.move_with(|map, selection| {
13999                    if selection.is_empty() {
14000                        let mut cursor = if action.ignore_newlines {
14001                            movement::previous_word_start(map, selection.head())
14002                        } else {
14003                            movement::previous_word_start_or_newline(map, selection.head())
14004                        };
14005                        cursor = movement::adjust_greedy_deletion(
14006                            map,
14007                            selection.head(),
14008                            cursor,
14009                            action.ignore_brackets,
14010                        );
14011                        selection.set_head(cursor, SelectionGoal::None);
14012                    }
14013                });
14014            });
14015            this.insert("", window, cx);
14016        });
14017    }
14018
14019    pub fn delete_to_previous_subword_start(
14020        &mut self,
14021        _: &DeleteToPreviousSubwordStart,
14022        window: &mut Window,
14023        cx: &mut Context<Self>,
14024    ) {
14025        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14026        self.transact(window, cx, |this, window, cx| {
14027            this.select_autoclose_pair(window, cx);
14028            this.change_selections(Default::default(), window, cx, |s| {
14029                s.move_with(|map, selection| {
14030                    if selection.is_empty() {
14031                        let mut cursor = movement::previous_subword_start(map, selection.head());
14032                        cursor =
14033                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14034                        selection.set_head(cursor, SelectionGoal::None);
14035                    }
14036                });
14037            });
14038            this.insert("", window, cx);
14039        });
14040    }
14041
14042    pub fn move_to_next_word_end(
14043        &mut self,
14044        _: &MoveToNextWordEnd,
14045        window: &mut Window,
14046        cx: &mut Context<Self>,
14047    ) {
14048        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14049        self.change_selections(Default::default(), window, cx, |s| {
14050            s.move_cursors_with(|map, head, _| {
14051                (movement::next_word_end(map, head), SelectionGoal::None)
14052            });
14053        })
14054    }
14055
14056    pub fn move_to_next_subword_end(
14057        &mut self,
14058        _: &MoveToNextSubwordEnd,
14059        window: &mut Window,
14060        cx: &mut Context<Self>,
14061    ) {
14062        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14063        self.change_selections(Default::default(), window, cx, |s| {
14064            s.move_cursors_with(|map, head, _| {
14065                (movement::next_subword_end(map, head), SelectionGoal::None)
14066            });
14067        })
14068    }
14069
14070    pub fn select_to_next_word_end(
14071        &mut self,
14072        _: &SelectToNextWordEnd,
14073        window: &mut Window,
14074        cx: &mut Context<Self>,
14075    ) {
14076        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14077        self.change_selections(Default::default(), window, cx, |s| {
14078            s.move_heads_with(|map, head, _| {
14079                (movement::next_word_end(map, head), SelectionGoal::None)
14080            });
14081        })
14082    }
14083
14084    pub fn select_to_next_subword_end(
14085        &mut self,
14086        _: &SelectToNextSubwordEnd,
14087        window: &mut Window,
14088        cx: &mut Context<Self>,
14089    ) {
14090        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14091        self.change_selections(Default::default(), window, cx, |s| {
14092            s.move_heads_with(|map, head, _| {
14093                (movement::next_subword_end(map, head), SelectionGoal::None)
14094            });
14095        })
14096    }
14097
14098    pub fn delete_to_next_word_end(
14099        &mut self,
14100        action: &DeleteToNextWordEnd,
14101        window: &mut Window,
14102        cx: &mut Context<Self>,
14103    ) {
14104        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14105        self.transact(window, cx, |this, window, cx| {
14106            this.change_selections(Default::default(), window, cx, |s| {
14107                s.move_with(|map, selection| {
14108                    if selection.is_empty() {
14109                        let mut cursor = if action.ignore_newlines {
14110                            movement::next_word_end(map, selection.head())
14111                        } else {
14112                            movement::next_word_end_or_newline(map, selection.head())
14113                        };
14114                        cursor = movement::adjust_greedy_deletion(
14115                            map,
14116                            selection.head(),
14117                            cursor,
14118                            action.ignore_brackets,
14119                        );
14120                        selection.set_head(cursor, SelectionGoal::None);
14121                    }
14122                });
14123            });
14124            this.insert("", window, cx);
14125        });
14126    }
14127
14128    pub fn delete_to_next_subword_end(
14129        &mut self,
14130        _: &DeleteToNextSubwordEnd,
14131        window: &mut Window,
14132        cx: &mut Context<Self>,
14133    ) {
14134        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14135        self.transact(window, cx, |this, window, cx| {
14136            this.change_selections(Default::default(), window, cx, |s| {
14137                s.move_with(|map, selection| {
14138                    if selection.is_empty() {
14139                        let mut cursor = movement::next_subword_end(map, selection.head());
14140                        cursor =
14141                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14142                        selection.set_head(cursor, SelectionGoal::None);
14143                    }
14144                });
14145            });
14146            this.insert("", window, cx);
14147        });
14148    }
14149
14150    pub fn move_to_beginning_of_line(
14151        &mut self,
14152        action: &MoveToBeginningOfLine,
14153        window: &mut Window,
14154        cx: &mut Context<Self>,
14155    ) {
14156        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14157        self.change_selections(Default::default(), window, cx, |s| {
14158            s.move_cursors_with(|map, head, _| {
14159                (
14160                    movement::indented_line_beginning(
14161                        map,
14162                        head,
14163                        action.stop_at_soft_wraps,
14164                        action.stop_at_indent,
14165                    ),
14166                    SelectionGoal::None,
14167                )
14168            });
14169        })
14170    }
14171
14172    pub fn select_to_beginning_of_line(
14173        &mut self,
14174        action: &SelectToBeginningOfLine,
14175        window: &mut Window,
14176        cx: &mut Context<Self>,
14177    ) {
14178        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14179        self.change_selections(Default::default(), window, cx, |s| {
14180            s.move_heads_with(|map, head, _| {
14181                (
14182                    movement::indented_line_beginning(
14183                        map,
14184                        head,
14185                        action.stop_at_soft_wraps,
14186                        action.stop_at_indent,
14187                    ),
14188                    SelectionGoal::None,
14189                )
14190            });
14191        });
14192    }
14193
14194    pub fn delete_to_beginning_of_line(
14195        &mut self,
14196        action: &DeleteToBeginningOfLine,
14197        window: &mut Window,
14198        cx: &mut Context<Self>,
14199    ) {
14200        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14201        self.transact(window, cx, |this, window, cx| {
14202            this.change_selections(Default::default(), window, cx, |s| {
14203                s.move_with(|_, selection| {
14204                    selection.reversed = true;
14205                });
14206            });
14207
14208            this.select_to_beginning_of_line(
14209                &SelectToBeginningOfLine {
14210                    stop_at_soft_wraps: false,
14211                    stop_at_indent: action.stop_at_indent,
14212                },
14213                window,
14214                cx,
14215            );
14216            this.backspace(&Backspace, window, cx);
14217        });
14218    }
14219
14220    pub fn move_to_end_of_line(
14221        &mut self,
14222        action: &MoveToEndOfLine,
14223        window: &mut Window,
14224        cx: &mut Context<Self>,
14225    ) {
14226        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14227        self.change_selections(Default::default(), window, cx, |s| {
14228            s.move_cursors_with(|map, head, _| {
14229                (
14230                    movement::line_end(map, head, action.stop_at_soft_wraps),
14231                    SelectionGoal::None,
14232                )
14233            });
14234        })
14235    }
14236
14237    pub fn select_to_end_of_line(
14238        &mut self,
14239        action: &SelectToEndOfLine,
14240        window: &mut Window,
14241        cx: &mut Context<Self>,
14242    ) {
14243        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14244        self.change_selections(Default::default(), window, cx, |s| {
14245            s.move_heads_with(|map, head, _| {
14246                (
14247                    movement::line_end(map, head, action.stop_at_soft_wraps),
14248                    SelectionGoal::None,
14249                )
14250            });
14251        })
14252    }
14253
14254    pub fn delete_to_end_of_line(
14255        &mut self,
14256        _: &DeleteToEndOfLine,
14257        window: &mut Window,
14258        cx: &mut Context<Self>,
14259    ) {
14260        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14261        self.transact(window, cx, |this, window, cx| {
14262            this.select_to_end_of_line(
14263                &SelectToEndOfLine {
14264                    stop_at_soft_wraps: false,
14265                },
14266                window,
14267                cx,
14268            );
14269            this.delete(&Delete, window, cx);
14270        });
14271    }
14272
14273    pub fn cut_to_end_of_line(
14274        &mut self,
14275        action: &CutToEndOfLine,
14276        window: &mut Window,
14277        cx: &mut Context<Self>,
14278    ) {
14279        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14280        self.transact(window, cx, |this, window, cx| {
14281            this.select_to_end_of_line(
14282                &SelectToEndOfLine {
14283                    stop_at_soft_wraps: false,
14284                },
14285                window,
14286                cx,
14287            );
14288            if !action.stop_at_newlines {
14289                this.change_selections(Default::default(), window, cx, |s| {
14290                    s.move_with(|_, sel| {
14291                        if sel.is_empty() {
14292                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14293                        }
14294                    });
14295                });
14296            }
14297            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14298            let item = this.cut_common(false, window, cx);
14299            cx.write_to_clipboard(item);
14300        });
14301    }
14302
14303    pub fn move_to_start_of_paragraph(
14304        &mut self,
14305        _: &MoveToStartOfParagraph,
14306        window: &mut Window,
14307        cx: &mut Context<Self>,
14308    ) {
14309        if matches!(self.mode, EditorMode::SingleLine) {
14310            cx.propagate();
14311            return;
14312        }
14313        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14314        self.change_selections(Default::default(), window, cx, |s| {
14315            s.move_with(|map, selection| {
14316                selection.collapse_to(
14317                    movement::start_of_paragraph(map, selection.head(), 1),
14318                    SelectionGoal::None,
14319                )
14320            });
14321        })
14322    }
14323
14324    pub fn move_to_end_of_paragraph(
14325        &mut self,
14326        _: &MoveToEndOfParagraph,
14327        window: &mut Window,
14328        cx: &mut Context<Self>,
14329    ) {
14330        if matches!(self.mode, EditorMode::SingleLine) {
14331            cx.propagate();
14332            return;
14333        }
14334        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14335        self.change_selections(Default::default(), window, cx, |s| {
14336            s.move_with(|map, selection| {
14337                selection.collapse_to(
14338                    movement::end_of_paragraph(map, selection.head(), 1),
14339                    SelectionGoal::None,
14340                )
14341            });
14342        })
14343    }
14344
14345    pub fn select_to_start_of_paragraph(
14346        &mut self,
14347        _: &SelectToStartOfParagraph,
14348        window: &mut Window,
14349        cx: &mut Context<Self>,
14350    ) {
14351        if matches!(self.mode, EditorMode::SingleLine) {
14352            cx.propagate();
14353            return;
14354        }
14355        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14356        self.change_selections(Default::default(), window, cx, |s| {
14357            s.move_heads_with(|map, head, _| {
14358                (
14359                    movement::start_of_paragraph(map, head, 1),
14360                    SelectionGoal::None,
14361                )
14362            });
14363        })
14364    }
14365
14366    pub fn select_to_end_of_paragraph(
14367        &mut self,
14368        _: &SelectToEndOfParagraph,
14369        window: &mut Window,
14370        cx: &mut Context<Self>,
14371    ) {
14372        if matches!(self.mode, EditorMode::SingleLine) {
14373            cx.propagate();
14374            return;
14375        }
14376        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14377        self.change_selections(Default::default(), window, cx, |s| {
14378            s.move_heads_with(|map, head, _| {
14379                (
14380                    movement::end_of_paragraph(map, head, 1),
14381                    SelectionGoal::None,
14382                )
14383            });
14384        })
14385    }
14386
14387    pub fn move_to_start_of_excerpt(
14388        &mut self,
14389        _: &MoveToStartOfExcerpt,
14390        window: &mut Window,
14391        cx: &mut Context<Self>,
14392    ) {
14393        if matches!(self.mode, EditorMode::SingleLine) {
14394            cx.propagate();
14395            return;
14396        }
14397        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14398        self.change_selections(Default::default(), window, cx, |s| {
14399            s.move_with(|map, selection| {
14400                selection.collapse_to(
14401                    movement::start_of_excerpt(
14402                        map,
14403                        selection.head(),
14404                        workspace::searchable::Direction::Prev,
14405                    ),
14406                    SelectionGoal::None,
14407                )
14408            });
14409        })
14410    }
14411
14412    pub fn move_to_start_of_next_excerpt(
14413        &mut self,
14414        _: &MoveToStartOfNextExcerpt,
14415        window: &mut Window,
14416        cx: &mut Context<Self>,
14417    ) {
14418        if matches!(self.mode, EditorMode::SingleLine) {
14419            cx.propagate();
14420            return;
14421        }
14422
14423        self.change_selections(Default::default(), window, cx, |s| {
14424            s.move_with(|map, selection| {
14425                selection.collapse_to(
14426                    movement::start_of_excerpt(
14427                        map,
14428                        selection.head(),
14429                        workspace::searchable::Direction::Next,
14430                    ),
14431                    SelectionGoal::None,
14432                )
14433            });
14434        })
14435    }
14436
14437    pub fn move_to_end_of_excerpt(
14438        &mut self,
14439        _: &MoveToEndOfExcerpt,
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::end_of_excerpt(
14452                        map,
14453                        selection.head(),
14454                        workspace::searchable::Direction::Next,
14455                    ),
14456                    SelectionGoal::None,
14457                )
14458            });
14459        })
14460    }
14461
14462    pub fn move_to_end_of_previous_excerpt(
14463        &mut self,
14464        _: &MoveToEndOfPreviousExcerpt,
14465        window: &mut Window,
14466        cx: &mut Context<Self>,
14467    ) {
14468        if matches!(self.mode, EditorMode::SingleLine) {
14469            cx.propagate();
14470            return;
14471        }
14472        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14473        self.change_selections(Default::default(), window, cx, |s| {
14474            s.move_with(|map, selection| {
14475                selection.collapse_to(
14476                    movement::end_of_excerpt(
14477                        map,
14478                        selection.head(),
14479                        workspace::searchable::Direction::Prev,
14480                    ),
14481                    SelectionGoal::None,
14482                )
14483            });
14484        })
14485    }
14486
14487    pub fn select_to_start_of_excerpt(
14488        &mut self,
14489        _: &SelectToStartOfExcerpt,
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_heads_with(|map, head, _| {
14500                (
14501                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14502                    SelectionGoal::None,
14503                )
14504            });
14505        })
14506    }
14507
14508    pub fn select_to_start_of_next_excerpt(
14509        &mut self,
14510        _: &SelectToStartOfNextExcerpt,
14511        window: &mut Window,
14512        cx: &mut Context<Self>,
14513    ) {
14514        if matches!(self.mode, EditorMode::SingleLine) {
14515            cx.propagate();
14516            return;
14517        }
14518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14519        self.change_selections(Default::default(), window, cx, |s| {
14520            s.move_heads_with(|map, head, _| {
14521                (
14522                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14523                    SelectionGoal::None,
14524                )
14525            });
14526        })
14527    }
14528
14529    pub fn select_to_end_of_excerpt(
14530        &mut self,
14531        _: &SelectToEndOfExcerpt,
14532        window: &mut Window,
14533        cx: &mut Context<Self>,
14534    ) {
14535        if matches!(self.mode, EditorMode::SingleLine) {
14536            cx.propagate();
14537            return;
14538        }
14539        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14540        self.change_selections(Default::default(), window, cx, |s| {
14541            s.move_heads_with(|map, head, _| {
14542                (
14543                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14544                    SelectionGoal::None,
14545                )
14546            });
14547        })
14548    }
14549
14550    pub fn select_to_end_of_previous_excerpt(
14551        &mut self,
14552        _: &SelectToEndOfPreviousExcerpt,
14553        window: &mut Window,
14554        cx: &mut Context<Self>,
14555    ) {
14556        if matches!(self.mode, EditorMode::SingleLine) {
14557            cx.propagate();
14558            return;
14559        }
14560        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14561        self.change_selections(Default::default(), window, cx, |s| {
14562            s.move_heads_with(|map, head, _| {
14563                (
14564                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14565                    SelectionGoal::None,
14566                )
14567            });
14568        })
14569    }
14570
14571    pub fn move_to_beginning(
14572        &mut self,
14573        _: &MoveToBeginning,
14574        window: &mut Window,
14575        cx: &mut Context<Self>,
14576    ) {
14577        if matches!(self.mode, EditorMode::SingleLine) {
14578            cx.propagate();
14579            return;
14580        }
14581        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14582        self.change_selections(Default::default(), window, cx, |s| {
14583            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14584        });
14585    }
14586
14587    pub fn select_to_beginning(
14588        &mut self,
14589        _: &SelectToBeginning,
14590        window: &mut Window,
14591        cx: &mut Context<Self>,
14592    ) {
14593        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14594        selection.set_head(Point::zero(), SelectionGoal::None);
14595        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14596        self.change_selections(Default::default(), window, cx, |s| {
14597            s.select(vec![selection]);
14598        });
14599    }
14600
14601    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14602        if matches!(self.mode, EditorMode::SingleLine) {
14603            cx.propagate();
14604            return;
14605        }
14606        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14607        let cursor = self.buffer.read(cx).read(cx).len();
14608        self.change_selections(Default::default(), window, cx, |s| {
14609            s.select_ranges(vec![cursor..cursor])
14610        });
14611    }
14612
14613    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14614        self.nav_history = nav_history;
14615    }
14616
14617    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14618        self.nav_history.as_ref()
14619    }
14620
14621    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14622        self.push_to_nav_history(
14623            self.selections.newest_anchor().head(),
14624            None,
14625            false,
14626            true,
14627            cx,
14628        );
14629    }
14630
14631    fn push_to_nav_history(
14632        &mut self,
14633        cursor_anchor: Anchor,
14634        new_position: Option<Point>,
14635        is_deactivate: bool,
14636        always: bool,
14637        cx: &mut Context<Self>,
14638    ) {
14639        if let Some(nav_history) = self.nav_history.as_mut() {
14640            let buffer = self.buffer.read(cx).read(cx);
14641            let cursor_position = cursor_anchor.to_point(&buffer);
14642            let scroll_state = self.scroll_manager.anchor();
14643            let scroll_top_row = scroll_state.top_row(&buffer);
14644            drop(buffer);
14645
14646            if let Some(new_position) = new_position {
14647                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14648                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14649                    return;
14650                }
14651            }
14652
14653            nav_history.push(
14654                Some(NavigationData {
14655                    cursor_anchor,
14656                    cursor_position,
14657                    scroll_anchor: scroll_state,
14658                    scroll_top_row,
14659                }),
14660                cx,
14661            );
14662            cx.emit(EditorEvent::PushedToNavHistory {
14663                anchor: cursor_anchor,
14664                is_deactivate,
14665            })
14666        }
14667    }
14668
14669    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14670        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14671        let buffer = self.buffer.read(cx).snapshot(cx);
14672        let mut selection = self
14673            .selections
14674            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14675        selection.set_head(buffer.len(), SelectionGoal::None);
14676        self.change_selections(Default::default(), window, cx, |s| {
14677            s.select(vec![selection]);
14678        });
14679    }
14680
14681    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14683        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14684            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14685        });
14686    }
14687
14688    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14689        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14690        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14691        let mut selections = self.selections.all::<Point>(&display_map);
14692        let max_point = display_map.buffer_snapshot().max_point();
14693        for selection in &mut selections {
14694            let rows = selection.spanned_rows(true, &display_map);
14695            selection.start = Point::new(rows.start.0, 0);
14696            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14697            selection.reversed = false;
14698        }
14699        self.change_selections(Default::default(), window, cx, |s| {
14700            s.select(selections);
14701        });
14702    }
14703
14704    pub fn split_selection_into_lines(
14705        &mut self,
14706        action: &SplitSelectionIntoLines,
14707        window: &mut Window,
14708        cx: &mut Context<Self>,
14709    ) {
14710        let selections = self
14711            .selections
14712            .all::<Point>(&self.display_snapshot(cx))
14713            .into_iter()
14714            .map(|selection| selection.start..selection.end)
14715            .collect::<Vec<_>>();
14716        self.unfold_ranges(&selections, true, true, cx);
14717
14718        let mut new_selection_ranges = Vec::new();
14719        {
14720            let buffer = self.buffer.read(cx).read(cx);
14721            for selection in selections {
14722                for row in selection.start.row..selection.end.row {
14723                    let line_start = Point::new(row, 0);
14724                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14725
14726                    if action.keep_selections {
14727                        // Keep the selection range for each line
14728                        let selection_start = if row == selection.start.row {
14729                            selection.start
14730                        } else {
14731                            line_start
14732                        };
14733                        new_selection_ranges.push(selection_start..line_end);
14734                    } else {
14735                        // Collapse to cursor at end of line
14736                        new_selection_ranges.push(line_end..line_end);
14737                    }
14738                }
14739
14740                let is_multiline_selection = selection.start.row != selection.end.row;
14741                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14742                // so this action feels more ergonomic when paired with other selection operations
14743                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14744                if !should_skip_last {
14745                    if action.keep_selections {
14746                        if is_multiline_selection {
14747                            let line_start = Point::new(selection.end.row, 0);
14748                            new_selection_ranges.push(line_start..selection.end);
14749                        } else {
14750                            new_selection_ranges.push(selection.start..selection.end);
14751                        }
14752                    } else {
14753                        new_selection_ranges.push(selection.end..selection.end);
14754                    }
14755                }
14756            }
14757        }
14758        self.change_selections(Default::default(), window, cx, |s| {
14759            s.select_ranges(new_selection_ranges);
14760        });
14761    }
14762
14763    pub fn add_selection_above(
14764        &mut self,
14765        action: &AddSelectionAbove,
14766        window: &mut Window,
14767        cx: &mut Context<Self>,
14768    ) {
14769        self.add_selection(true, action.skip_soft_wrap, window, cx);
14770    }
14771
14772    pub fn add_selection_below(
14773        &mut self,
14774        action: &AddSelectionBelow,
14775        window: &mut Window,
14776        cx: &mut Context<Self>,
14777    ) {
14778        self.add_selection(false, action.skip_soft_wrap, window, cx);
14779    }
14780
14781    fn add_selection(
14782        &mut self,
14783        above: bool,
14784        skip_soft_wrap: bool,
14785        window: &mut Window,
14786        cx: &mut Context<Self>,
14787    ) {
14788        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14789
14790        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14791        let all_selections = self.selections.all::<Point>(&display_map);
14792        let text_layout_details = self.text_layout_details(window);
14793
14794        let (mut columnar_selections, new_selections_to_columnarize) = {
14795            if let Some(state) = self.add_selections_state.as_ref() {
14796                let columnar_selection_ids: HashSet<_> = state
14797                    .groups
14798                    .iter()
14799                    .flat_map(|group| group.stack.iter())
14800                    .copied()
14801                    .collect();
14802
14803                all_selections
14804                    .into_iter()
14805                    .partition(|s| columnar_selection_ids.contains(&s.id))
14806            } else {
14807                (Vec::new(), all_selections)
14808            }
14809        };
14810
14811        let mut state = self
14812            .add_selections_state
14813            .take()
14814            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14815
14816        for selection in new_selections_to_columnarize {
14817            let range = selection.display_range(&display_map).sorted();
14818            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14819            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14820            let positions = start_x.min(end_x)..start_x.max(end_x);
14821            let mut stack = Vec::new();
14822            for row in range.start.row().0..=range.end.row().0 {
14823                if let Some(selection) = self.selections.build_columnar_selection(
14824                    &display_map,
14825                    DisplayRow(row),
14826                    &positions,
14827                    selection.reversed,
14828                    &text_layout_details,
14829                ) {
14830                    stack.push(selection.id);
14831                    columnar_selections.push(selection);
14832                }
14833            }
14834            if !stack.is_empty() {
14835                if above {
14836                    stack.reverse();
14837                }
14838                state.groups.push(AddSelectionsGroup { above, stack });
14839            }
14840        }
14841
14842        let mut final_selections = Vec::new();
14843        let end_row = if above {
14844            DisplayRow(0)
14845        } else {
14846            display_map.max_point().row()
14847        };
14848
14849        let mut last_added_item_per_group = HashMap::default();
14850        for group in state.groups.iter_mut() {
14851            if let Some(last_id) = group.stack.last() {
14852                last_added_item_per_group.insert(*last_id, group);
14853            }
14854        }
14855
14856        for selection in columnar_selections {
14857            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14858                if above == group.above {
14859                    let range = selection.display_range(&display_map).sorted();
14860                    debug_assert_eq!(range.start.row(), range.end.row());
14861                    let mut row = range.start.row();
14862                    let positions =
14863                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14864                            Pixels::from(start)..Pixels::from(end)
14865                        } else {
14866                            let start_x =
14867                                display_map.x_for_display_point(range.start, &text_layout_details);
14868                            let end_x =
14869                                display_map.x_for_display_point(range.end, &text_layout_details);
14870                            start_x.min(end_x)..start_x.max(end_x)
14871                        };
14872
14873                    let mut maybe_new_selection = None;
14874                    let direction = if above { -1 } else { 1 };
14875
14876                    while row != end_row {
14877                        if skip_soft_wrap {
14878                            row = display_map
14879                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14880                                .row();
14881                        } else if above {
14882                            row.0 -= 1;
14883                        } else {
14884                            row.0 += 1;
14885                        }
14886
14887                        if let Some(new_selection) = self.selections.build_columnar_selection(
14888                            &display_map,
14889                            row,
14890                            &positions,
14891                            selection.reversed,
14892                            &text_layout_details,
14893                        ) {
14894                            maybe_new_selection = Some(new_selection);
14895                            break;
14896                        }
14897                    }
14898
14899                    if let Some(new_selection) = maybe_new_selection {
14900                        group.stack.push(new_selection.id);
14901                        if above {
14902                            final_selections.push(new_selection);
14903                            final_selections.push(selection);
14904                        } else {
14905                            final_selections.push(selection);
14906                            final_selections.push(new_selection);
14907                        }
14908                    } else {
14909                        final_selections.push(selection);
14910                    }
14911                } else {
14912                    group.stack.pop();
14913                }
14914            } else {
14915                final_selections.push(selection);
14916            }
14917        }
14918
14919        self.change_selections(Default::default(), window, cx, |s| {
14920            s.select(final_selections);
14921        });
14922
14923        let final_selection_ids: HashSet<_> = self
14924            .selections
14925            .all::<Point>(&display_map)
14926            .iter()
14927            .map(|s| s.id)
14928            .collect();
14929        state.groups.retain_mut(|group| {
14930            // selections might get merged above so we remove invalid items from stacks
14931            group.stack.retain(|id| final_selection_ids.contains(id));
14932
14933            // single selection in stack can be treated as initial state
14934            group.stack.len() > 1
14935        });
14936
14937        if !state.groups.is_empty() {
14938            self.add_selections_state = Some(state);
14939        }
14940    }
14941
14942    pub fn insert_snippet_at_selections(
14943        &mut self,
14944        action: &InsertSnippet,
14945        window: &mut Window,
14946        cx: &mut Context<Self>,
14947    ) {
14948        self.try_insert_snippet_at_selections(action, window, cx)
14949            .log_err();
14950    }
14951
14952    fn try_insert_snippet_at_selections(
14953        &mut self,
14954        action: &InsertSnippet,
14955        window: &mut Window,
14956        cx: &mut Context<Self>,
14957    ) -> Result<()> {
14958        let insertion_ranges = self
14959            .selections
14960            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
14961            .into_iter()
14962            .map(|selection| selection.range())
14963            .collect_vec();
14964
14965        let snippet = if let Some(snippet_body) = &action.snippet {
14966            if action.language.is_none() && action.name.is_none() {
14967                Snippet::parse(snippet_body)?
14968            } else {
14969                bail!("`snippet` is mutually exclusive with `language` and `name`")
14970            }
14971        } else if let Some(name) = &action.name {
14972            let project = self.project().context("no project")?;
14973            let snippet_store = project.read(cx).snippets().read(cx);
14974            let snippet = snippet_store
14975                .snippets_for(action.language.clone(), cx)
14976                .into_iter()
14977                .find(|snippet| snippet.name == *name)
14978                .context("snippet not found")?;
14979            Snippet::parse(&snippet.body)?
14980        } else {
14981            // todo(andrew): open modal to select snippet
14982            bail!("`name` or `snippet` is required")
14983        };
14984
14985        self.insert_snippet(&insertion_ranges, snippet, window, cx)
14986    }
14987
14988    fn select_match_ranges(
14989        &mut self,
14990        range: Range<MultiBufferOffset>,
14991        reversed: bool,
14992        replace_newest: bool,
14993        auto_scroll: Option<Autoscroll>,
14994        window: &mut Window,
14995        cx: &mut Context<Editor>,
14996    ) {
14997        self.unfold_ranges(
14998            std::slice::from_ref(&range),
14999            false,
15000            auto_scroll.is_some(),
15001            cx,
15002        );
15003        let effects = if let Some(scroll) = auto_scroll {
15004            SelectionEffects::scroll(scroll)
15005        } else {
15006            SelectionEffects::no_scroll()
15007        };
15008        self.change_selections(effects, window, cx, |s| {
15009            if replace_newest {
15010                s.delete(s.newest_anchor().id);
15011            }
15012            if reversed {
15013                s.insert_range(range.end..range.start);
15014            } else {
15015                s.insert_range(range);
15016            }
15017        });
15018    }
15019
15020    pub fn select_next_match_internal(
15021        &mut self,
15022        display_map: &DisplaySnapshot,
15023        replace_newest: bool,
15024        autoscroll: Option<Autoscroll>,
15025        window: &mut Window,
15026        cx: &mut Context<Self>,
15027    ) -> Result<()> {
15028        let buffer = display_map.buffer_snapshot();
15029        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15030        if let Some(mut select_next_state) = self.select_next_state.take() {
15031            let query = &select_next_state.query;
15032            if !select_next_state.done {
15033                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15034                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15035                let mut next_selected_range = None;
15036
15037                let bytes_after_last_selection =
15038                    buffer.bytes_in_range(last_selection.end..buffer.len());
15039                let bytes_before_first_selection =
15040                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15041                let query_matches = query
15042                    .stream_find_iter(bytes_after_last_selection)
15043                    .map(|result| (last_selection.end, result))
15044                    .chain(
15045                        query
15046                            .stream_find_iter(bytes_before_first_selection)
15047                            .map(|result| (MultiBufferOffset(0), result)),
15048                    );
15049
15050                for (start_offset, query_match) in query_matches {
15051                    let query_match = query_match.unwrap(); // can only fail due to I/O
15052                    let offset_range =
15053                        start_offset + query_match.start()..start_offset + query_match.end();
15054
15055                    if !select_next_state.wordwise
15056                        || (!buffer.is_inside_word(offset_range.start, None)
15057                            && !buffer.is_inside_word(offset_range.end, None))
15058                    {
15059                        let idx = selections
15060                            .partition_point(|selection| selection.end <= offset_range.start);
15061                        let overlaps = selections
15062                            .get(idx)
15063                            .map_or(false, |selection| selection.start < offset_range.end);
15064
15065                        if !overlaps {
15066                            next_selected_range = Some(offset_range);
15067                            break;
15068                        }
15069                    }
15070                }
15071
15072                if let Some(next_selected_range) = next_selected_range {
15073                    self.select_match_ranges(
15074                        next_selected_range,
15075                        last_selection.reversed,
15076                        replace_newest,
15077                        autoscroll,
15078                        window,
15079                        cx,
15080                    );
15081                } else {
15082                    select_next_state.done = true;
15083                }
15084            }
15085
15086            self.select_next_state = Some(select_next_state);
15087        } else {
15088            let mut only_carets = true;
15089            let mut same_text_selected = true;
15090            let mut selected_text = None;
15091
15092            let mut selections_iter = selections.iter().peekable();
15093            while let Some(selection) = selections_iter.next() {
15094                if selection.start != selection.end {
15095                    only_carets = false;
15096                }
15097
15098                if same_text_selected {
15099                    if selected_text.is_none() {
15100                        selected_text =
15101                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15102                    }
15103
15104                    if let Some(next_selection) = selections_iter.peek() {
15105                        if next_selection.len() == selection.len() {
15106                            let next_selected_text = buffer
15107                                .text_for_range(next_selection.range())
15108                                .collect::<String>();
15109                            if Some(next_selected_text) != selected_text {
15110                                same_text_selected = false;
15111                                selected_text = None;
15112                            }
15113                        } else {
15114                            same_text_selected = false;
15115                            selected_text = None;
15116                        }
15117                    }
15118                }
15119            }
15120
15121            if only_carets {
15122                for selection in &mut selections {
15123                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15124                    selection.start = word_range.start;
15125                    selection.end = word_range.end;
15126                    selection.goal = SelectionGoal::None;
15127                    selection.reversed = false;
15128                    self.select_match_ranges(
15129                        selection.start..selection.end,
15130                        selection.reversed,
15131                        replace_newest,
15132                        autoscroll,
15133                        window,
15134                        cx,
15135                    );
15136                }
15137
15138                if selections.len() == 1 {
15139                    let selection = selections
15140                        .last()
15141                        .expect("ensured that there's only one selection");
15142                    let query = buffer
15143                        .text_for_range(selection.start..selection.end)
15144                        .collect::<String>();
15145                    let is_empty = query.is_empty();
15146                    let select_state = SelectNextState {
15147                        query: self.build_query(&[query], cx)?,
15148                        wordwise: true,
15149                        done: is_empty,
15150                    };
15151                    self.select_next_state = Some(select_state);
15152                } else {
15153                    self.select_next_state = None;
15154                }
15155            } else if let Some(selected_text) = selected_text {
15156                self.select_next_state = Some(SelectNextState {
15157                    query: self.build_query(&[selected_text], cx)?,
15158                    wordwise: false,
15159                    done: false,
15160                });
15161                self.select_next_match_internal(
15162                    display_map,
15163                    replace_newest,
15164                    autoscroll,
15165                    window,
15166                    cx,
15167                )?;
15168            }
15169        }
15170        Ok(())
15171    }
15172
15173    pub fn select_all_matches(
15174        &mut self,
15175        _action: &SelectAllMatches,
15176        window: &mut Window,
15177        cx: &mut Context<Self>,
15178    ) -> Result<()> {
15179        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15180
15181        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15182
15183        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15184        let Some(select_next_state) = self.select_next_state.as_mut() else {
15185            return Ok(());
15186        };
15187        if select_next_state.done {
15188            return Ok(());
15189        }
15190
15191        let mut new_selections = Vec::new();
15192
15193        let reversed = self
15194            .selections
15195            .oldest::<MultiBufferOffset>(&display_map)
15196            .reversed;
15197        let buffer = display_map.buffer_snapshot();
15198        let query_matches = select_next_state
15199            .query
15200            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15201
15202        for query_match in query_matches.into_iter() {
15203            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15204            let offset_range = if reversed {
15205                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15206            } else {
15207                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15208            };
15209
15210            if !select_next_state.wordwise
15211                || (!buffer.is_inside_word(offset_range.start, None)
15212                    && !buffer.is_inside_word(offset_range.end, None))
15213            {
15214                new_selections.push(offset_range.start..offset_range.end);
15215            }
15216        }
15217
15218        select_next_state.done = true;
15219
15220        if new_selections.is_empty() {
15221            log::error!("bug: new_selections is empty in select_all_matches");
15222            return Ok(());
15223        }
15224
15225        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15226        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15227            selections.select_ranges(new_selections)
15228        });
15229
15230        Ok(())
15231    }
15232
15233    pub fn select_next(
15234        &mut self,
15235        action: &SelectNext,
15236        window: &mut Window,
15237        cx: &mut Context<Self>,
15238    ) -> Result<()> {
15239        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15240        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15241        self.select_next_match_internal(
15242            &display_map,
15243            action.replace_newest,
15244            Some(Autoscroll::newest()),
15245            window,
15246            cx,
15247        )?;
15248        Ok(())
15249    }
15250
15251    pub fn select_previous(
15252        &mut self,
15253        action: &SelectPrevious,
15254        window: &mut Window,
15255        cx: &mut Context<Self>,
15256    ) -> Result<()> {
15257        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15258        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15259        let buffer = display_map.buffer_snapshot();
15260        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15261        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15262            let query = &select_prev_state.query;
15263            if !select_prev_state.done {
15264                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15265                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15266                let mut next_selected_range = None;
15267                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15268                let bytes_before_last_selection =
15269                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15270                let bytes_after_first_selection =
15271                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15272                let query_matches = query
15273                    .stream_find_iter(bytes_before_last_selection)
15274                    .map(|result| (last_selection.start, result))
15275                    .chain(
15276                        query
15277                            .stream_find_iter(bytes_after_first_selection)
15278                            .map(|result| (buffer.len(), result)),
15279                    );
15280                for (end_offset, query_match) in query_matches {
15281                    let query_match = query_match.unwrap(); // can only fail due to I/O
15282                    let offset_range =
15283                        end_offset - query_match.end()..end_offset - query_match.start();
15284
15285                    if !select_prev_state.wordwise
15286                        || (!buffer.is_inside_word(offset_range.start, None)
15287                            && !buffer.is_inside_word(offset_range.end, None))
15288                    {
15289                        next_selected_range = Some(offset_range);
15290                        break;
15291                    }
15292                }
15293
15294                if let Some(next_selected_range) = next_selected_range {
15295                    self.select_match_ranges(
15296                        next_selected_range,
15297                        last_selection.reversed,
15298                        action.replace_newest,
15299                        Some(Autoscroll::newest()),
15300                        window,
15301                        cx,
15302                    );
15303                } else {
15304                    select_prev_state.done = true;
15305                }
15306            }
15307
15308            self.select_prev_state = Some(select_prev_state);
15309        } else {
15310            let mut only_carets = true;
15311            let mut same_text_selected = true;
15312            let mut selected_text = None;
15313
15314            let mut selections_iter = selections.iter().peekable();
15315            while let Some(selection) = selections_iter.next() {
15316                if selection.start != selection.end {
15317                    only_carets = false;
15318                }
15319
15320                if same_text_selected {
15321                    if selected_text.is_none() {
15322                        selected_text =
15323                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15324                    }
15325
15326                    if let Some(next_selection) = selections_iter.peek() {
15327                        if next_selection.len() == selection.len() {
15328                            let next_selected_text = buffer
15329                                .text_for_range(next_selection.range())
15330                                .collect::<String>();
15331                            if Some(next_selected_text) != selected_text {
15332                                same_text_selected = false;
15333                                selected_text = None;
15334                            }
15335                        } else {
15336                            same_text_selected = false;
15337                            selected_text = None;
15338                        }
15339                    }
15340                }
15341            }
15342
15343            if only_carets {
15344                for selection in &mut selections {
15345                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15346                    selection.start = word_range.start;
15347                    selection.end = word_range.end;
15348                    selection.goal = SelectionGoal::None;
15349                    selection.reversed = false;
15350                    self.select_match_ranges(
15351                        selection.start..selection.end,
15352                        selection.reversed,
15353                        action.replace_newest,
15354                        Some(Autoscroll::newest()),
15355                        window,
15356                        cx,
15357                    );
15358                }
15359                if selections.len() == 1 {
15360                    let selection = selections
15361                        .last()
15362                        .expect("ensured that there's only one selection");
15363                    let query = buffer
15364                        .text_for_range(selection.start..selection.end)
15365                        .collect::<String>();
15366                    let is_empty = query.is_empty();
15367                    let select_state = SelectNextState {
15368                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15369                        wordwise: true,
15370                        done: is_empty,
15371                    };
15372                    self.select_prev_state = Some(select_state);
15373                } else {
15374                    self.select_prev_state = None;
15375                }
15376            } else if let Some(selected_text) = selected_text {
15377                self.select_prev_state = Some(SelectNextState {
15378                    query: self
15379                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15380                    wordwise: false,
15381                    done: false,
15382                });
15383                self.select_previous(action, window, cx)?;
15384            }
15385        }
15386        Ok(())
15387    }
15388
15389    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15390    /// setting the case sensitivity based on the global
15391    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15392    /// editor's settings.
15393    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15394    where
15395        I: IntoIterator<Item = P>,
15396        P: AsRef<[u8]>,
15397    {
15398        let case_sensitive = self
15399            .select_next_is_case_sensitive
15400            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15401
15402        let mut builder = AhoCorasickBuilder::new();
15403        builder.ascii_case_insensitive(!case_sensitive);
15404        builder.build(patterns)
15405    }
15406
15407    pub fn find_next_match(
15408        &mut self,
15409        _: &FindNextMatch,
15410        window: &mut Window,
15411        cx: &mut Context<Self>,
15412    ) -> Result<()> {
15413        let selections = self.selections.disjoint_anchors_arc();
15414        match selections.first() {
15415            Some(first) if selections.len() >= 2 => {
15416                self.change_selections(Default::default(), window, cx, |s| {
15417                    s.select_ranges([first.range()]);
15418                });
15419            }
15420            _ => self.select_next(
15421                &SelectNext {
15422                    replace_newest: true,
15423                },
15424                window,
15425                cx,
15426            )?,
15427        }
15428        Ok(())
15429    }
15430
15431    pub fn find_previous_match(
15432        &mut self,
15433        _: &FindPreviousMatch,
15434        window: &mut Window,
15435        cx: &mut Context<Self>,
15436    ) -> Result<()> {
15437        let selections = self.selections.disjoint_anchors_arc();
15438        match selections.last() {
15439            Some(last) if selections.len() >= 2 => {
15440                self.change_selections(Default::default(), window, cx, |s| {
15441                    s.select_ranges([last.range()]);
15442                });
15443            }
15444            _ => self.select_previous(
15445                &SelectPrevious {
15446                    replace_newest: true,
15447                },
15448                window,
15449                cx,
15450            )?,
15451        }
15452        Ok(())
15453    }
15454
15455    pub fn toggle_comments(
15456        &mut self,
15457        action: &ToggleComments,
15458        window: &mut Window,
15459        cx: &mut Context<Self>,
15460    ) {
15461        if self.read_only(cx) {
15462            return;
15463        }
15464        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15465        let text_layout_details = &self.text_layout_details(window);
15466        self.transact(window, cx, |this, window, cx| {
15467            let mut selections = this
15468                .selections
15469                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15470            let mut edits = Vec::new();
15471            let mut selection_edit_ranges = Vec::new();
15472            let mut last_toggled_row = None;
15473            let snapshot = this.buffer.read(cx).read(cx);
15474            let empty_str: Arc<str> = Arc::default();
15475            let mut suffixes_inserted = Vec::new();
15476            let ignore_indent = action.ignore_indent;
15477
15478            fn comment_prefix_range(
15479                snapshot: &MultiBufferSnapshot,
15480                row: MultiBufferRow,
15481                comment_prefix: &str,
15482                comment_prefix_whitespace: &str,
15483                ignore_indent: bool,
15484            ) -> Range<Point> {
15485                let indent_size = if ignore_indent {
15486                    0
15487                } else {
15488                    snapshot.indent_size_for_line(row).len
15489                };
15490
15491                let start = Point::new(row.0, indent_size);
15492
15493                let mut line_bytes = snapshot
15494                    .bytes_in_range(start..snapshot.max_point())
15495                    .flatten()
15496                    .copied();
15497
15498                // If this line currently begins with the line comment prefix, then record
15499                // the range containing the prefix.
15500                if line_bytes
15501                    .by_ref()
15502                    .take(comment_prefix.len())
15503                    .eq(comment_prefix.bytes())
15504                {
15505                    // Include any whitespace that matches the comment prefix.
15506                    let matching_whitespace_len = line_bytes
15507                        .zip(comment_prefix_whitespace.bytes())
15508                        .take_while(|(a, b)| a == b)
15509                        .count() as u32;
15510                    let end = Point::new(
15511                        start.row,
15512                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15513                    );
15514                    start..end
15515                } else {
15516                    start..start
15517                }
15518            }
15519
15520            fn comment_suffix_range(
15521                snapshot: &MultiBufferSnapshot,
15522                row: MultiBufferRow,
15523                comment_suffix: &str,
15524                comment_suffix_has_leading_space: bool,
15525            ) -> Range<Point> {
15526                let end = Point::new(row.0, snapshot.line_len(row));
15527                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15528
15529                let mut line_end_bytes = snapshot
15530                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15531                    .flatten()
15532                    .copied();
15533
15534                let leading_space_len = if suffix_start_column > 0
15535                    && line_end_bytes.next() == Some(b' ')
15536                    && comment_suffix_has_leading_space
15537                {
15538                    1
15539                } else {
15540                    0
15541                };
15542
15543                // If this line currently begins with the line comment prefix, then record
15544                // the range containing the prefix.
15545                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15546                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15547                    start..end
15548                } else {
15549                    end..end
15550                }
15551            }
15552
15553            // TODO: Handle selections that cross excerpts
15554            for selection in &mut selections {
15555                let start_column = snapshot
15556                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15557                    .len;
15558                let language = if let Some(language) =
15559                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15560                {
15561                    language
15562                } else {
15563                    continue;
15564                };
15565
15566                selection_edit_ranges.clear();
15567
15568                // If multiple selections contain a given row, avoid processing that
15569                // row more than once.
15570                let mut start_row = MultiBufferRow(selection.start.row);
15571                if last_toggled_row == Some(start_row) {
15572                    start_row = start_row.next_row();
15573                }
15574                let end_row =
15575                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15576                        MultiBufferRow(selection.end.row - 1)
15577                    } else {
15578                        MultiBufferRow(selection.end.row)
15579                    };
15580                last_toggled_row = Some(end_row);
15581
15582                if start_row > end_row {
15583                    continue;
15584                }
15585
15586                // If the language has line comments, toggle those.
15587                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15588
15589                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15590                if ignore_indent {
15591                    full_comment_prefixes = full_comment_prefixes
15592                        .into_iter()
15593                        .map(|s| Arc::from(s.trim_end()))
15594                        .collect();
15595                }
15596
15597                if !full_comment_prefixes.is_empty() {
15598                    let first_prefix = full_comment_prefixes
15599                        .first()
15600                        .expect("prefixes is non-empty");
15601                    let prefix_trimmed_lengths = full_comment_prefixes
15602                        .iter()
15603                        .map(|p| p.trim_end_matches(' ').len())
15604                        .collect::<SmallVec<[usize; 4]>>();
15605
15606                    let mut all_selection_lines_are_comments = true;
15607
15608                    for row in start_row.0..=end_row.0 {
15609                        let row = MultiBufferRow(row);
15610                        if start_row < end_row && snapshot.is_line_blank(row) {
15611                            continue;
15612                        }
15613
15614                        let prefix_range = full_comment_prefixes
15615                            .iter()
15616                            .zip(prefix_trimmed_lengths.iter().copied())
15617                            .map(|(prefix, trimmed_prefix_len)| {
15618                                comment_prefix_range(
15619                                    snapshot.deref(),
15620                                    row,
15621                                    &prefix[..trimmed_prefix_len],
15622                                    &prefix[trimmed_prefix_len..],
15623                                    ignore_indent,
15624                                )
15625                            })
15626                            .max_by_key(|range| range.end.column - range.start.column)
15627                            .expect("prefixes is non-empty");
15628
15629                        if prefix_range.is_empty() {
15630                            all_selection_lines_are_comments = false;
15631                        }
15632
15633                        selection_edit_ranges.push(prefix_range);
15634                    }
15635
15636                    if all_selection_lines_are_comments {
15637                        edits.extend(
15638                            selection_edit_ranges
15639                                .iter()
15640                                .cloned()
15641                                .map(|range| (range, empty_str.clone())),
15642                        );
15643                    } else {
15644                        let min_column = selection_edit_ranges
15645                            .iter()
15646                            .map(|range| range.start.column)
15647                            .min()
15648                            .unwrap_or(0);
15649                        edits.extend(selection_edit_ranges.iter().map(|range| {
15650                            let position = Point::new(range.start.row, min_column);
15651                            (position..position, first_prefix.clone())
15652                        }));
15653                    }
15654                } else if let Some(BlockCommentConfig {
15655                    start: full_comment_prefix,
15656                    end: comment_suffix,
15657                    ..
15658                }) = language.block_comment()
15659                {
15660                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15661                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15662                    let prefix_range = comment_prefix_range(
15663                        snapshot.deref(),
15664                        start_row,
15665                        comment_prefix,
15666                        comment_prefix_whitespace,
15667                        ignore_indent,
15668                    );
15669                    let suffix_range = comment_suffix_range(
15670                        snapshot.deref(),
15671                        end_row,
15672                        comment_suffix.trim_start_matches(' '),
15673                        comment_suffix.starts_with(' '),
15674                    );
15675
15676                    if prefix_range.is_empty() || suffix_range.is_empty() {
15677                        edits.push((
15678                            prefix_range.start..prefix_range.start,
15679                            full_comment_prefix.clone(),
15680                        ));
15681                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15682                        suffixes_inserted.push((end_row, comment_suffix.len()));
15683                    } else {
15684                        edits.push((prefix_range, empty_str.clone()));
15685                        edits.push((suffix_range, empty_str.clone()));
15686                    }
15687                } else {
15688                    continue;
15689                }
15690            }
15691
15692            drop(snapshot);
15693            this.buffer.update(cx, |buffer, cx| {
15694                buffer.edit(edits, None, cx);
15695            });
15696
15697            // Adjust selections so that they end before any comment suffixes that
15698            // were inserted.
15699            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15700            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15701            let snapshot = this.buffer.read(cx).read(cx);
15702            for selection in &mut selections {
15703                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15704                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15705                        Ordering::Less => {
15706                            suffixes_inserted.next();
15707                            continue;
15708                        }
15709                        Ordering::Greater => break,
15710                        Ordering::Equal => {
15711                            if selection.end.column == snapshot.line_len(row) {
15712                                if selection.is_empty() {
15713                                    selection.start.column -= suffix_len as u32;
15714                                }
15715                                selection.end.column -= suffix_len as u32;
15716                            }
15717                            break;
15718                        }
15719                    }
15720                }
15721            }
15722
15723            drop(snapshot);
15724            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15725
15726            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15727            let selections_on_single_row = selections.windows(2).all(|selections| {
15728                selections[0].start.row == selections[1].start.row
15729                    && selections[0].end.row == selections[1].end.row
15730                    && selections[0].start.row == selections[0].end.row
15731            });
15732            let selections_selecting = selections
15733                .iter()
15734                .any(|selection| selection.start != selection.end);
15735            let advance_downwards = action.advance_downwards
15736                && selections_on_single_row
15737                && !selections_selecting
15738                && !matches!(this.mode, EditorMode::SingleLine);
15739
15740            if advance_downwards {
15741                let snapshot = this.buffer.read(cx).snapshot(cx);
15742
15743                this.change_selections(Default::default(), window, cx, |s| {
15744                    s.move_cursors_with(|display_snapshot, display_point, _| {
15745                        let mut point = display_point.to_point(display_snapshot);
15746                        point.row += 1;
15747                        point = snapshot.clip_point(point, Bias::Left);
15748                        let display_point = point.to_display_point(display_snapshot);
15749                        let goal = SelectionGoal::HorizontalPosition(
15750                            display_snapshot
15751                                .x_for_display_point(display_point, text_layout_details)
15752                                .into(),
15753                        );
15754                        (display_point, goal)
15755                    })
15756                });
15757            }
15758        });
15759    }
15760
15761    pub fn select_enclosing_symbol(
15762        &mut self,
15763        _: &SelectEnclosingSymbol,
15764        window: &mut Window,
15765        cx: &mut Context<Self>,
15766    ) {
15767        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15768
15769        let buffer = self.buffer.read(cx).snapshot(cx);
15770        let old_selections = self
15771            .selections
15772            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15773            .into_boxed_slice();
15774
15775        fn update_selection(
15776            selection: &Selection<MultiBufferOffset>,
15777            buffer_snap: &MultiBufferSnapshot,
15778        ) -> Option<Selection<MultiBufferOffset>> {
15779            let cursor = selection.head();
15780            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15781            for symbol in symbols.iter().rev() {
15782                let start = symbol.range.start.to_offset(buffer_snap);
15783                let end = symbol.range.end.to_offset(buffer_snap);
15784                let new_range = start..end;
15785                if start < selection.start || end > selection.end {
15786                    return Some(Selection {
15787                        id: selection.id,
15788                        start: new_range.start,
15789                        end: new_range.end,
15790                        goal: SelectionGoal::None,
15791                        reversed: selection.reversed,
15792                    });
15793                }
15794            }
15795            None
15796        }
15797
15798        let mut selected_larger_symbol = false;
15799        let new_selections = old_selections
15800            .iter()
15801            .map(|selection| match update_selection(selection, &buffer) {
15802                Some(new_selection) => {
15803                    if new_selection.range() != selection.range() {
15804                        selected_larger_symbol = true;
15805                    }
15806                    new_selection
15807                }
15808                None => selection.clone(),
15809            })
15810            .collect::<Vec<_>>();
15811
15812        if selected_larger_symbol {
15813            self.change_selections(Default::default(), window, cx, |s| {
15814                s.select(new_selections);
15815            });
15816        }
15817    }
15818
15819    pub fn select_larger_syntax_node(
15820        &mut self,
15821        _: &SelectLargerSyntaxNode,
15822        window: &mut Window,
15823        cx: &mut Context<Self>,
15824    ) {
15825        let Some(visible_row_count) = self.visible_row_count() else {
15826            return;
15827        };
15828        let old_selections: Box<[_]> = self
15829            .selections
15830            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15831            .into();
15832        if old_selections.is_empty() {
15833            return;
15834        }
15835
15836        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15837
15838        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15839        let buffer = self.buffer.read(cx).snapshot(cx);
15840
15841        let mut selected_larger_node = false;
15842        let mut new_selections = old_selections
15843            .iter()
15844            .map(|selection| {
15845                let old_range = selection.start..selection.end;
15846
15847                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15848                    // manually select word at selection
15849                    if ["string_content", "inline"].contains(&node.kind()) {
15850                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15851                        // ignore if word is already selected
15852                        if !word_range.is_empty() && old_range != word_range {
15853                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15854                            // only select word if start and end point belongs to same word
15855                            if word_range == last_word_range {
15856                                selected_larger_node = true;
15857                                return Selection {
15858                                    id: selection.id,
15859                                    start: word_range.start,
15860                                    end: word_range.end,
15861                                    goal: SelectionGoal::None,
15862                                    reversed: selection.reversed,
15863                                };
15864                            }
15865                        }
15866                    }
15867                }
15868
15869                let mut new_range = old_range.clone();
15870                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15871                    new_range = range;
15872                    if !node.is_named() {
15873                        continue;
15874                    }
15875                    if !display_map.intersects_fold(new_range.start)
15876                        && !display_map.intersects_fold(new_range.end)
15877                    {
15878                        break;
15879                    }
15880                }
15881
15882                selected_larger_node |= new_range != old_range;
15883                Selection {
15884                    id: selection.id,
15885                    start: new_range.start,
15886                    end: new_range.end,
15887                    goal: SelectionGoal::None,
15888                    reversed: selection.reversed,
15889                }
15890            })
15891            .collect::<Vec<_>>();
15892
15893        if !selected_larger_node {
15894            return; // don't put this call in the history
15895        }
15896
15897        // scroll based on transformation done to the last selection created by the user
15898        let (last_old, last_new) = old_selections
15899            .last()
15900            .zip(new_selections.last().cloned())
15901            .expect("old_selections isn't empty");
15902
15903        // revert selection
15904        let is_selection_reversed = {
15905            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15906            new_selections.last_mut().expect("checked above").reversed =
15907                should_newest_selection_be_reversed;
15908            should_newest_selection_be_reversed
15909        };
15910
15911        if selected_larger_node {
15912            self.select_syntax_node_history.disable_clearing = true;
15913            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15914                s.select(new_selections.clone());
15915            });
15916            self.select_syntax_node_history.disable_clearing = false;
15917        }
15918
15919        let start_row = last_new.start.to_display_point(&display_map).row().0;
15920        let end_row = last_new.end.to_display_point(&display_map).row().0;
15921        let selection_height = end_row - start_row + 1;
15922        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15923
15924        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15925        let scroll_behavior = if fits_on_the_screen {
15926            self.request_autoscroll(Autoscroll::fit(), cx);
15927            SelectSyntaxNodeScrollBehavior::FitSelection
15928        } else if is_selection_reversed {
15929            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15930            SelectSyntaxNodeScrollBehavior::CursorTop
15931        } else {
15932            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15933            SelectSyntaxNodeScrollBehavior::CursorBottom
15934        };
15935
15936        self.select_syntax_node_history.push((
15937            old_selections,
15938            scroll_behavior,
15939            is_selection_reversed,
15940        ));
15941    }
15942
15943    pub fn select_smaller_syntax_node(
15944        &mut self,
15945        _: &SelectSmallerSyntaxNode,
15946        window: &mut Window,
15947        cx: &mut Context<Self>,
15948    ) {
15949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15950
15951        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15952            self.select_syntax_node_history.pop()
15953        {
15954            if let Some(selection) = selections.last_mut() {
15955                selection.reversed = is_selection_reversed;
15956            }
15957
15958            self.select_syntax_node_history.disable_clearing = true;
15959            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15960                s.select(selections.to_vec());
15961            });
15962            self.select_syntax_node_history.disable_clearing = false;
15963
15964            match scroll_behavior {
15965                SelectSyntaxNodeScrollBehavior::CursorTop => {
15966                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15967                }
15968                SelectSyntaxNodeScrollBehavior::FitSelection => {
15969                    self.request_autoscroll(Autoscroll::fit(), cx);
15970                }
15971                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15972                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15973                }
15974            }
15975        }
15976    }
15977
15978    pub fn unwrap_syntax_node(
15979        &mut self,
15980        _: &UnwrapSyntaxNode,
15981        window: &mut Window,
15982        cx: &mut Context<Self>,
15983    ) {
15984        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15985
15986        let buffer = self.buffer.read(cx).snapshot(cx);
15987        let selections = self
15988            .selections
15989            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15990            .into_iter()
15991            // subtracting the offset requires sorting
15992            .sorted_by_key(|i| i.start);
15993
15994        let full_edits = selections
15995            .into_iter()
15996            .filter_map(|selection| {
15997                let child = if selection.is_empty()
15998                    && let Some((_, ancestor_range)) =
15999                        buffer.syntax_ancestor(selection.start..selection.end)
16000                {
16001                    ancestor_range
16002                } else {
16003                    selection.range()
16004                };
16005
16006                let mut parent = child.clone();
16007                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16008                    parent = ancestor_range;
16009                    if parent.start < child.start || parent.end > child.end {
16010                        break;
16011                    }
16012                }
16013
16014                if parent == child {
16015                    return None;
16016                }
16017                let text = buffer.text_for_range(child).collect::<String>();
16018                Some((selection.id, parent, text))
16019            })
16020            .collect::<Vec<_>>();
16021        if full_edits.is_empty() {
16022            return;
16023        }
16024
16025        self.transact(window, cx, |this, window, cx| {
16026            this.buffer.update(cx, |buffer, cx| {
16027                buffer.edit(
16028                    full_edits
16029                        .iter()
16030                        .map(|(_, p, t)| (p.clone(), t.clone()))
16031                        .collect::<Vec<_>>(),
16032                    None,
16033                    cx,
16034                );
16035            });
16036            this.change_selections(Default::default(), window, cx, |s| {
16037                let mut offset = 0;
16038                let mut selections = vec![];
16039                for (id, parent, text) in full_edits {
16040                    let start = parent.start - offset;
16041                    offset += (parent.end - parent.start) - text.len();
16042                    selections.push(Selection {
16043                        id,
16044                        start,
16045                        end: start + text.len(),
16046                        reversed: false,
16047                        goal: Default::default(),
16048                    });
16049                }
16050                s.select(selections);
16051            });
16052        });
16053    }
16054
16055    pub fn select_next_syntax_node(
16056        &mut self,
16057        _: &SelectNextSyntaxNode,
16058        window: &mut Window,
16059        cx: &mut Context<Self>,
16060    ) {
16061        let old_selections: Box<[_]> = self
16062            .selections
16063            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16064            .into();
16065        if old_selections.is_empty() {
16066            return;
16067        }
16068
16069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16070
16071        let buffer = self.buffer.read(cx).snapshot(cx);
16072        let mut selected_sibling = false;
16073
16074        let new_selections = old_selections
16075            .iter()
16076            .map(|selection| {
16077                let old_range = selection.start..selection.end;
16078
16079                let old_range =
16080                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16081                let excerpt = buffer.excerpt_containing(old_range.clone());
16082
16083                if let Some(mut excerpt) = excerpt
16084                    && let Some(node) = excerpt
16085                        .buffer()
16086                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16087                {
16088                    let new_range = excerpt.map_range_from_buffer(
16089                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16090                    );
16091                    selected_sibling = true;
16092                    Selection {
16093                        id: selection.id,
16094                        start: new_range.start,
16095                        end: new_range.end,
16096                        goal: SelectionGoal::None,
16097                        reversed: selection.reversed,
16098                    }
16099                } else {
16100                    selection.clone()
16101                }
16102            })
16103            .collect::<Vec<_>>();
16104
16105        if selected_sibling {
16106            self.change_selections(
16107                SelectionEffects::scroll(Autoscroll::fit()),
16108                window,
16109                cx,
16110                |s| {
16111                    s.select(new_selections);
16112                },
16113            );
16114        }
16115    }
16116
16117    pub fn select_prev_syntax_node(
16118        &mut self,
16119        _: &SelectPreviousSyntaxNode,
16120        window: &mut Window,
16121        cx: &mut Context<Self>,
16122    ) {
16123        let old_selections: Box<[_]> = self
16124            .selections
16125            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16126            .into();
16127        if old_selections.is_empty() {
16128            return;
16129        }
16130
16131        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16132
16133        let buffer = self.buffer.read(cx).snapshot(cx);
16134        let mut selected_sibling = false;
16135
16136        let new_selections = old_selections
16137            .iter()
16138            .map(|selection| {
16139                let old_range = selection.start..selection.end;
16140                let old_range =
16141                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16142                let excerpt = buffer.excerpt_containing(old_range.clone());
16143
16144                if let Some(mut excerpt) = excerpt
16145                    && let Some(node) = excerpt
16146                        .buffer()
16147                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16148                {
16149                    let new_range = excerpt.map_range_from_buffer(
16150                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16151                    );
16152                    selected_sibling = true;
16153                    Selection {
16154                        id: selection.id,
16155                        start: new_range.start,
16156                        end: new_range.end,
16157                        goal: SelectionGoal::None,
16158                        reversed: selection.reversed,
16159                    }
16160                } else {
16161                    selection.clone()
16162                }
16163            })
16164            .collect::<Vec<_>>();
16165
16166        if selected_sibling {
16167            self.change_selections(
16168                SelectionEffects::scroll(Autoscroll::fit()),
16169                window,
16170                cx,
16171                |s| {
16172                    s.select(new_selections);
16173                },
16174            );
16175        }
16176    }
16177
16178    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16179        if !EditorSettings::get_global(cx).gutter.runnables {
16180            self.clear_tasks();
16181            return Task::ready(());
16182        }
16183        let project = self.project().map(Entity::downgrade);
16184        let task_sources = self.lsp_task_sources(cx);
16185        let multi_buffer = self.buffer.downgrade();
16186        cx.spawn_in(window, async move |editor, cx| {
16187            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16188            let Some(project) = project.and_then(|p| p.upgrade()) else {
16189                return;
16190            };
16191            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16192                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16193            }) else {
16194                return;
16195            };
16196
16197            let hide_runnables = project
16198                .update(cx, |project, _| project.is_via_collab())
16199                .unwrap_or(true);
16200            if hide_runnables {
16201                return;
16202            }
16203            let new_rows =
16204                cx.background_spawn({
16205                    let snapshot = display_snapshot.clone();
16206                    async move {
16207                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16208                    }
16209                })
16210                    .await;
16211            let Ok(lsp_tasks) =
16212                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16213            else {
16214                return;
16215            };
16216            let lsp_tasks = lsp_tasks.await;
16217
16218            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16219                lsp_tasks
16220                    .into_iter()
16221                    .flat_map(|(kind, tasks)| {
16222                        tasks.into_iter().filter_map(move |(location, task)| {
16223                            Some((kind.clone(), location?, task))
16224                        })
16225                    })
16226                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16227                        let buffer = location.target.buffer;
16228                        let buffer_snapshot = buffer.read(cx).snapshot();
16229                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16230                            |(excerpt_id, snapshot, _)| {
16231                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16232                                    display_snapshot
16233                                        .buffer_snapshot()
16234                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16235                                } else {
16236                                    None
16237                                }
16238                            },
16239                        );
16240                        if let Some(offset) = offset {
16241                            let task_buffer_range =
16242                                location.target.range.to_point(&buffer_snapshot);
16243                            let context_buffer_range =
16244                                task_buffer_range.to_offset(&buffer_snapshot);
16245                            let context_range = BufferOffset(context_buffer_range.start)
16246                                ..BufferOffset(context_buffer_range.end);
16247
16248                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16249                                .or_insert_with(|| RunnableTasks {
16250                                    templates: Vec::new(),
16251                                    offset,
16252                                    column: task_buffer_range.start.column,
16253                                    extra_variables: HashMap::default(),
16254                                    context_range,
16255                                })
16256                                .templates
16257                                .push((kind, task.original_task().clone()));
16258                        }
16259
16260                        acc
16261                    })
16262            }) else {
16263                return;
16264            };
16265
16266            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16267                buffer.language_settings(cx).tasks.prefer_lsp
16268            }) else {
16269                return;
16270            };
16271
16272            let rows = Self::runnable_rows(
16273                project,
16274                display_snapshot,
16275                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16276                new_rows,
16277                cx.clone(),
16278            )
16279            .await;
16280            editor
16281                .update(cx, |editor, _| {
16282                    editor.clear_tasks();
16283                    for (key, mut value) in rows {
16284                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16285                            value.templates.extend(lsp_tasks.templates);
16286                        }
16287
16288                        editor.insert_tasks(key, value);
16289                    }
16290                    for (key, value) in lsp_tasks_by_rows {
16291                        editor.insert_tasks(key, value);
16292                    }
16293                })
16294                .ok();
16295        })
16296    }
16297    fn fetch_runnable_ranges(
16298        snapshot: &DisplaySnapshot,
16299        range: Range<Anchor>,
16300    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16301        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16302    }
16303
16304    fn runnable_rows(
16305        project: Entity<Project>,
16306        snapshot: DisplaySnapshot,
16307        prefer_lsp: bool,
16308        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16309        cx: AsyncWindowContext,
16310    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16311        cx.spawn(async move |cx| {
16312            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16313            for (run_range, mut runnable) in runnable_ranges {
16314                let Some(tasks) = cx
16315                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16316                    .ok()
16317                else {
16318                    continue;
16319                };
16320                let mut tasks = tasks.await;
16321
16322                if prefer_lsp {
16323                    tasks.retain(|(task_kind, _)| {
16324                        !matches!(task_kind, TaskSourceKind::Language { .. })
16325                    });
16326                }
16327                if tasks.is_empty() {
16328                    continue;
16329                }
16330
16331                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16332                let Some(row) = snapshot
16333                    .buffer_snapshot()
16334                    .buffer_line_for_row(MultiBufferRow(point.row))
16335                    .map(|(_, range)| range.start.row)
16336                else {
16337                    continue;
16338                };
16339
16340                let context_range =
16341                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16342                runnable_rows.push((
16343                    (runnable.buffer_id, row),
16344                    RunnableTasks {
16345                        templates: tasks,
16346                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16347                        context_range,
16348                        column: point.column,
16349                        extra_variables: runnable.extra_captures,
16350                    },
16351                ));
16352            }
16353            runnable_rows
16354        })
16355    }
16356
16357    fn templates_with_tags(
16358        project: &Entity<Project>,
16359        runnable: &mut Runnable,
16360        cx: &mut App,
16361    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16362        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16363            let (worktree_id, file) = project
16364                .buffer_for_id(runnable.buffer, cx)
16365                .and_then(|buffer| buffer.read(cx).file())
16366                .map(|file| (file.worktree_id(cx), file.clone()))
16367                .unzip();
16368
16369            (
16370                project.task_store().read(cx).task_inventory().cloned(),
16371                worktree_id,
16372                file,
16373            )
16374        });
16375
16376        let tags = mem::take(&mut runnable.tags);
16377        let language = runnable.language.clone();
16378        cx.spawn(async move |cx| {
16379            let mut templates_with_tags = Vec::new();
16380            if let Some(inventory) = inventory {
16381                for RunnableTag(tag) in tags {
16382                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16383                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16384                    }) else {
16385                        return templates_with_tags;
16386                    };
16387                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16388                        move |(_, template)| {
16389                            template.tags.iter().any(|source_tag| source_tag == &tag)
16390                        },
16391                    ));
16392                }
16393            }
16394            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16395
16396            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16397                // Strongest source wins; if we have worktree tag binding, prefer that to
16398                // global and language bindings;
16399                // if we have a global binding, prefer that to language binding.
16400                let first_mismatch = templates_with_tags
16401                    .iter()
16402                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16403                if let Some(index) = first_mismatch {
16404                    templates_with_tags.truncate(index);
16405                }
16406            }
16407
16408            templates_with_tags
16409        })
16410    }
16411
16412    pub fn move_to_enclosing_bracket(
16413        &mut self,
16414        _: &MoveToEnclosingBracket,
16415        window: &mut Window,
16416        cx: &mut Context<Self>,
16417    ) {
16418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16419        self.change_selections(Default::default(), window, cx, |s| {
16420            s.move_offsets_with(|snapshot, selection| {
16421                let Some(enclosing_bracket_ranges) =
16422                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16423                else {
16424                    return;
16425                };
16426
16427                let mut best_length = usize::MAX;
16428                let mut best_inside = false;
16429                let mut best_in_bracket_range = false;
16430                let mut best_destination = None;
16431                for (open, close) in enclosing_bracket_ranges {
16432                    let close = close.to_inclusive();
16433                    let length = *close.end() - open.start;
16434                    let inside = selection.start >= open.end && selection.end <= *close.start();
16435                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16436                        || close.contains(&selection.head());
16437
16438                    // If best is next to a bracket and current isn't, skip
16439                    if !in_bracket_range && best_in_bracket_range {
16440                        continue;
16441                    }
16442
16443                    // Prefer smaller lengths unless best is inside and current isn't
16444                    if length > best_length && (best_inside || !inside) {
16445                        continue;
16446                    }
16447
16448                    best_length = length;
16449                    best_inside = inside;
16450                    best_in_bracket_range = in_bracket_range;
16451                    best_destination = Some(
16452                        if close.contains(&selection.start) && close.contains(&selection.end) {
16453                            if inside { open.end } else { open.start }
16454                        } else if inside {
16455                            *close.start()
16456                        } else {
16457                            *close.end()
16458                        },
16459                    );
16460                }
16461
16462                if let Some(destination) = best_destination {
16463                    selection.collapse_to(destination, SelectionGoal::None);
16464                }
16465            })
16466        });
16467    }
16468
16469    pub fn undo_selection(
16470        &mut self,
16471        _: &UndoSelection,
16472        window: &mut Window,
16473        cx: &mut Context<Self>,
16474    ) {
16475        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16476        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16477            self.selection_history.mode = SelectionHistoryMode::Undoing;
16478            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16479                this.end_selection(window, cx);
16480                this.change_selections(
16481                    SelectionEffects::scroll(Autoscroll::newest()),
16482                    window,
16483                    cx,
16484                    |s| s.select_anchors(entry.selections.to_vec()),
16485                );
16486            });
16487            self.selection_history.mode = SelectionHistoryMode::Normal;
16488
16489            self.select_next_state = entry.select_next_state;
16490            self.select_prev_state = entry.select_prev_state;
16491            self.add_selections_state = entry.add_selections_state;
16492        }
16493    }
16494
16495    pub fn redo_selection(
16496        &mut self,
16497        _: &RedoSelection,
16498        window: &mut Window,
16499        cx: &mut Context<Self>,
16500    ) {
16501        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16502        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16503            self.selection_history.mode = SelectionHistoryMode::Redoing;
16504            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16505                this.end_selection(window, cx);
16506                this.change_selections(
16507                    SelectionEffects::scroll(Autoscroll::newest()),
16508                    window,
16509                    cx,
16510                    |s| s.select_anchors(entry.selections.to_vec()),
16511                );
16512            });
16513            self.selection_history.mode = SelectionHistoryMode::Normal;
16514
16515            self.select_next_state = entry.select_next_state;
16516            self.select_prev_state = entry.select_prev_state;
16517            self.add_selections_state = entry.add_selections_state;
16518        }
16519    }
16520
16521    pub fn expand_excerpts(
16522        &mut self,
16523        action: &ExpandExcerpts,
16524        _: &mut Window,
16525        cx: &mut Context<Self>,
16526    ) {
16527        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16528    }
16529
16530    pub fn expand_excerpts_down(
16531        &mut self,
16532        action: &ExpandExcerptsDown,
16533        _: &mut Window,
16534        cx: &mut Context<Self>,
16535    ) {
16536        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16537    }
16538
16539    pub fn expand_excerpts_up(
16540        &mut self,
16541        action: &ExpandExcerptsUp,
16542        _: &mut Window,
16543        cx: &mut Context<Self>,
16544    ) {
16545        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16546    }
16547
16548    pub fn expand_excerpts_for_direction(
16549        &mut self,
16550        lines: u32,
16551        direction: ExpandExcerptDirection,
16552
16553        cx: &mut Context<Self>,
16554    ) {
16555        let selections = self.selections.disjoint_anchors_arc();
16556
16557        let lines = if lines == 0 {
16558            EditorSettings::get_global(cx).expand_excerpt_lines
16559        } else {
16560            lines
16561        };
16562
16563        self.buffer.update(cx, |buffer, cx| {
16564            let snapshot = buffer.snapshot(cx);
16565            let mut excerpt_ids = selections
16566                .iter()
16567                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16568                .collect::<Vec<_>>();
16569            excerpt_ids.sort();
16570            excerpt_ids.dedup();
16571            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16572        })
16573    }
16574
16575    pub fn expand_excerpt(
16576        &mut self,
16577        excerpt: ExcerptId,
16578        direction: ExpandExcerptDirection,
16579        window: &mut Window,
16580        cx: &mut Context<Self>,
16581    ) {
16582        let current_scroll_position = self.scroll_position(cx);
16583        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16584        let mut scroll = None;
16585
16586        if direction == ExpandExcerptDirection::Down {
16587            let multi_buffer = self.buffer.read(cx);
16588            let snapshot = multi_buffer.snapshot(cx);
16589            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16590                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16591                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16592            {
16593                let buffer_snapshot = buffer.read(cx).snapshot();
16594                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16595                let last_row = buffer_snapshot.max_point().row;
16596                let lines_below = last_row.saturating_sub(excerpt_end_row);
16597                if lines_below >= lines_to_expand {
16598                    scroll = Some(
16599                        current_scroll_position
16600                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16601                    );
16602                }
16603            }
16604        }
16605        if direction == ExpandExcerptDirection::Up
16606            && self
16607                .buffer
16608                .read(cx)
16609                .snapshot(cx)
16610                .excerpt_before(excerpt)
16611                .is_none()
16612        {
16613            scroll = Some(current_scroll_position);
16614        }
16615
16616        self.buffer.update(cx, |buffer, cx| {
16617            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16618        });
16619
16620        if let Some(new_scroll_position) = scroll {
16621            self.set_scroll_position(new_scroll_position, window, cx);
16622        }
16623    }
16624
16625    pub fn go_to_singleton_buffer_point(
16626        &mut self,
16627        point: Point,
16628        window: &mut Window,
16629        cx: &mut Context<Self>,
16630    ) {
16631        self.go_to_singleton_buffer_range(point..point, window, cx);
16632    }
16633
16634    pub fn go_to_singleton_buffer_range(
16635        &mut self,
16636        range: Range<Point>,
16637        window: &mut Window,
16638        cx: &mut Context<Self>,
16639    ) {
16640        let multibuffer = self.buffer().read(cx);
16641        let Some(buffer) = multibuffer.as_singleton() else {
16642            return;
16643        };
16644        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16645            return;
16646        };
16647        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16648            return;
16649        };
16650        self.change_selections(
16651            SelectionEffects::default().nav_history(true),
16652            window,
16653            cx,
16654            |s| s.select_anchor_ranges([start..end]),
16655        );
16656    }
16657
16658    pub fn go_to_diagnostic(
16659        &mut self,
16660        action: &GoToDiagnostic,
16661        window: &mut Window,
16662        cx: &mut Context<Self>,
16663    ) {
16664        if !self.diagnostics_enabled() {
16665            return;
16666        }
16667        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16668        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16669    }
16670
16671    pub fn go_to_prev_diagnostic(
16672        &mut self,
16673        action: &GoToPreviousDiagnostic,
16674        window: &mut Window,
16675        cx: &mut Context<Self>,
16676    ) {
16677        if !self.diagnostics_enabled() {
16678            return;
16679        }
16680        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16681        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16682    }
16683
16684    pub fn go_to_diagnostic_impl(
16685        &mut self,
16686        direction: Direction,
16687        severity: GoToDiagnosticSeverityFilter,
16688        window: &mut Window,
16689        cx: &mut Context<Self>,
16690    ) {
16691        let buffer = self.buffer.read(cx).snapshot(cx);
16692        let selection = self
16693            .selections
16694            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16695
16696        let mut active_group_id = None;
16697        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16698            && active_group.active_range.start.to_offset(&buffer) == selection.start
16699        {
16700            active_group_id = Some(active_group.group_id);
16701        }
16702
16703        fn filtered<'a>(
16704            severity: GoToDiagnosticSeverityFilter,
16705            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16706        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16707            diagnostics
16708                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16709                .filter(|entry| entry.range.start != entry.range.end)
16710                .filter(|entry| !entry.diagnostic.is_unnecessary)
16711        }
16712
16713        let before = filtered(
16714            severity,
16715            buffer
16716                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16717                .filter(|entry| entry.range.start <= selection.start),
16718        );
16719        let after = filtered(
16720            severity,
16721            buffer
16722                .diagnostics_in_range(selection.start..buffer.len())
16723                .filter(|entry| entry.range.start >= selection.start),
16724        );
16725
16726        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16727        if direction == Direction::Prev {
16728            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16729            {
16730                for diagnostic in prev_diagnostics.into_iter().rev() {
16731                    if diagnostic.range.start != selection.start
16732                        || active_group_id
16733                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16734                    {
16735                        found = Some(diagnostic);
16736                        break 'outer;
16737                    }
16738                }
16739            }
16740        } else {
16741            for diagnostic in after.chain(before) {
16742                if diagnostic.range.start != selection.start
16743                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16744                {
16745                    found = Some(diagnostic);
16746                    break;
16747                }
16748            }
16749        }
16750        let Some(next_diagnostic) = found else {
16751            return;
16752        };
16753
16754        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16755        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16756            return;
16757        };
16758        let snapshot = self.snapshot(window, cx);
16759        if snapshot.intersects_fold(next_diagnostic.range.start) {
16760            self.unfold_ranges(
16761                std::slice::from_ref(&next_diagnostic.range),
16762                true,
16763                false,
16764                cx,
16765            );
16766        }
16767        self.change_selections(Default::default(), window, cx, |s| {
16768            s.select_ranges(vec![
16769                next_diagnostic.range.start..next_diagnostic.range.start,
16770            ])
16771        });
16772        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16773        self.refresh_edit_prediction(false, true, window, cx);
16774    }
16775
16776    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16778        let snapshot = self.snapshot(window, cx);
16779        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16780        self.go_to_hunk_before_or_after_position(
16781            &snapshot,
16782            selection.head(),
16783            Direction::Next,
16784            window,
16785            cx,
16786        );
16787    }
16788
16789    pub fn go_to_hunk_before_or_after_position(
16790        &mut self,
16791        snapshot: &EditorSnapshot,
16792        position: Point,
16793        direction: Direction,
16794        window: &mut Window,
16795        cx: &mut Context<Editor>,
16796    ) {
16797        let row = if direction == Direction::Next {
16798            self.hunk_after_position(snapshot, position)
16799                .map(|hunk| hunk.row_range.start)
16800        } else {
16801            self.hunk_before_position(snapshot, position)
16802        };
16803
16804        if let Some(row) = row {
16805            let destination = Point::new(row.0, 0);
16806            let autoscroll = Autoscroll::center();
16807
16808            self.unfold_ranges(&[destination..destination], false, false, cx);
16809            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16810                s.select_ranges([destination..destination]);
16811            });
16812        }
16813    }
16814
16815    fn hunk_after_position(
16816        &mut self,
16817        snapshot: &EditorSnapshot,
16818        position: Point,
16819    ) -> Option<MultiBufferDiffHunk> {
16820        snapshot
16821            .buffer_snapshot()
16822            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16823            .find(|hunk| hunk.row_range.start.0 > position.row)
16824            .or_else(|| {
16825                snapshot
16826                    .buffer_snapshot()
16827                    .diff_hunks_in_range(Point::zero()..position)
16828                    .find(|hunk| hunk.row_range.end.0 < position.row)
16829            })
16830    }
16831
16832    fn go_to_prev_hunk(
16833        &mut self,
16834        _: &GoToPreviousHunk,
16835        window: &mut Window,
16836        cx: &mut Context<Self>,
16837    ) {
16838        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16839        let snapshot = self.snapshot(window, cx);
16840        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16841        self.go_to_hunk_before_or_after_position(
16842            &snapshot,
16843            selection.head(),
16844            Direction::Prev,
16845            window,
16846            cx,
16847        );
16848    }
16849
16850    fn hunk_before_position(
16851        &mut self,
16852        snapshot: &EditorSnapshot,
16853        position: Point,
16854    ) -> Option<MultiBufferRow> {
16855        snapshot
16856            .buffer_snapshot()
16857            .diff_hunk_before(position)
16858            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16859    }
16860
16861    fn go_to_next_change(
16862        &mut self,
16863        _: &GoToNextChange,
16864        window: &mut Window,
16865        cx: &mut Context<Self>,
16866    ) {
16867        if let Some(selections) = self
16868            .change_list
16869            .next_change(1, Direction::Next)
16870            .map(|s| s.to_vec())
16871        {
16872            self.change_selections(Default::default(), window, cx, |s| {
16873                let map = s.display_snapshot();
16874                s.select_display_ranges(selections.iter().map(|a| {
16875                    let point = a.to_display_point(&map);
16876                    point..point
16877                }))
16878            })
16879        }
16880    }
16881
16882    fn go_to_previous_change(
16883        &mut self,
16884        _: &GoToPreviousChange,
16885        window: &mut Window,
16886        cx: &mut Context<Self>,
16887    ) {
16888        if let Some(selections) = self
16889            .change_list
16890            .next_change(1, Direction::Prev)
16891            .map(|s| s.to_vec())
16892        {
16893            self.change_selections(Default::default(), window, cx, |s| {
16894                let map = s.display_snapshot();
16895                s.select_display_ranges(selections.iter().map(|a| {
16896                    let point = a.to_display_point(&map);
16897                    point..point
16898                }))
16899            })
16900        }
16901    }
16902
16903    pub fn go_to_next_document_highlight(
16904        &mut self,
16905        _: &GoToNextDocumentHighlight,
16906        window: &mut Window,
16907        cx: &mut Context<Self>,
16908    ) {
16909        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16910    }
16911
16912    pub fn go_to_prev_document_highlight(
16913        &mut self,
16914        _: &GoToPreviousDocumentHighlight,
16915        window: &mut Window,
16916        cx: &mut Context<Self>,
16917    ) {
16918        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16919    }
16920
16921    pub fn go_to_document_highlight_before_or_after_position(
16922        &mut self,
16923        direction: Direction,
16924        window: &mut Window,
16925        cx: &mut Context<Editor>,
16926    ) {
16927        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16928        let snapshot = self.snapshot(window, cx);
16929        let buffer = &snapshot.buffer_snapshot();
16930        let position = self
16931            .selections
16932            .newest::<Point>(&snapshot.display_snapshot)
16933            .head();
16934        let anchor_position = buffer.anchor_after(position);
16935
16936        // Get all document highlights (both read and write)
16937        let mut all_highlights = Vec::new();
16938
16939        if let Some((_, read_highlights)) = self
16940            .background_highlights
16941            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16942        {
16943            all_highlights.extend(read_highlights.iter());
16944        }
16945
16946        if let Some((_, write_highlights)) = self
16947            .background_highlights
16948            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16949        {
16950            all_highlights.extend(write_highlights.iter());
16951        }
16952
16953        if all_highlights.is_empty() {
16954            return;
16955        }
16956
16957        // Sort highlights by position
16958        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16959
16960        let target_highlight = match direction {
16961            Direction::Next => {
16962                // Find the first highlight after the current position
16963                all_highlights
16964                    .iter()
16965                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16966            }
16967            Direction::Prev => {
16968                // Find the last highlight before the current position
16969                all_highlights
16970                    .iter()
16971                    .rev()
16972                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16973            }
16974        };
16975
16976        if let Some(highlight) = target_highlight {
16977            let destination = highlight.start.to_point(buffer);
16978            let autoscroll = Autoscroll::center();
16979
16980            self.unfold_ranges(&[destination..destination], false, false, cx);
16981            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16982                s.select_ranges([destination..destination]);
16983            });
16984        }
16985    }
16986
16987    fn go_to_line<T: 'static>(
16988        &mut self,
16989        position: Anchor,
16990        highlight_color: Option<Hsla>,
16991        window: &mut Window,
16992        cx: &mut Context<Self>,
16993    ) {
16994        let snapshot = self.snapshot(window, cx).display_snapshot;
16995        let position = position.to_point(&snapshot.buffer_snapshot());
16996        let start = snapshot
16997            .buffer_snapshot()
16998            .clip_point(Point::new(position.row, 0), Bias::Left);
16999        let end = start + Point::new(1, 0);
17000        let start = snapshot.buffer_snapshot().anchor_before(start);
17001        let end = snapshot.buffer_snapshot().anchor_before(end);
17002
17003        self.highlight_rows::<T>(
17004            start..end,
17005            highlight_color
17006                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17007            Default::default(),
17008            cx,
17009        );
17010
17011        if self.buffer.read(cx).is_singleton() {
17012            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17013        }
17014    }
17015
17016    pub fn go_to_definition(
17017        &mut self,
17018        _: &GoToDefinition,
17019        window: &mut Window,
17020        cx: &mut Context<Self>,
17021    ) -> Task<Result<Navigated>> {
17022        let definition =
17023            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17024        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17025        cx.spawn_in(window, async move |editor, cx| {
17026            if definition.await? == Navigated::Yes {
17027                return Ok(Navigated::Yes);
17028            }
17029            match fallback_strategy {
17030                GoToDefinitionFallback::None => Ok(Navigated::No),
17031                GoToDefinitionFallback::FindAllReferences => {
17032                    match editor.update_in(cx, |editor, window, cx| {
17033                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17034                    })? {
17035                        Some(references) => references.await,
17036                        None => Ok(Navigated::No),
17037                    }
17038                }
17039            }
17040        })
17041    }
17042
17043    pub fn go_to_declaration(
17044        &mut self,
17045        _: &GoToDeclaration,
17046        window: &mut Window,
17047        cx: &mut Context<Self>,
17048    ) -> Task<Result<Navigated>> {
17049        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17050    }
17051
17052    pub fn go_to_declaration_split(
17053        &mut self,
17054        _: &GoToDeclaration,
17055        window: &mut Window,
17056        cx: &mut Context<Self>,
17057    ) -> Task<Result<Navigated>> {
17058        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17059    }
17060
17061    pub fn go_to_implementation(
17062        &mut self,
17063        _: &GoToImplementation,
17064        window: &mut Window,
17065        cx: &mut Context<Self>,
17066    ) -> Task<Result<Navigated>> {
17067        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17068    }
17069
17070    pub fn go_to_implementation_split(
17071        &mut self,
17072        _: &GoToImplementationSplit,
17073        window: &mut Window,
17074        cx: &mut Context<Self>,
17075    ) -> Task<Result<Navigated>> {
17076        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17077    }
17078
17079    pub fn go_to_type_definition(
17080        &mut self,
17081        _: &GoToTypeDefinition,
17082        window: &mut Window,
17083        cx: &mut Context<Self>,
17084    ) -> Task<Result<Navigated>> {
17085        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17086    }
17087
17088    pub fn go_to_definition_split(
17089        &mut self,
17090        _: &GoToDefinitionSplit,
17091        window: &mut Window,
17092        cx: &mut Context<Self>,
17093    ) -> Task<Result<Navigated>> {
17094        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17095    }
17096
17097    pub fn go_to_type_definition_split(
17098        &mut self,
17099        _: &GoToTypeDefinitionSplit,
17100        window: &mut Window,
17101        cx: &mut Context<Self>,
17102    ) -> Task<Result<Navigated>> {
17103        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17104    }
17105
17106    fn go_to_definition_of_kind(
17107        &mut self,
17108        kind: GotoDefinitionKind,
17109        split: bool,
17110        window: &mut Window,
17111        cx: &mut Context<Self>,
17112    ) -> Task<Result<Navigated>> {
17113        let Some(provider) = self.semantics_provider.clone() else {
17114            return Task::ready(Ok(Navigated::No));
17115        };
17116        let head = self
17117            .selections
17118            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17119            .head();
17120        let buffer = self.buffer.read(cx);
17121        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17122            return Task::ready(Ok(Navigated::No));
17123        };
17124        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17125            return Task::ready(Ok(Navigated::No));
17126        };
17127
17128        cx.spawn_in(window, async move |editor, cx| {
17129            let Some(definitions) = definitions.await? else {
17130                return Ok(Navigated::No);
17131            };
17132            let navigated = editor
17133                .update_in(cx, |editor, window, cx| {
17134                    editor.navigate_to_hover_links(
17135                        Some(kind),
17136                        definitions
17137                            .into_iter()
17138                            .filter(|location| {
17139                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17140                            })
17141                            .map(HoverLink::Text)
17142                            .collect::<Vec<_>>(),
17143                        split,
17144                        window,
17145                        cx,
17146                    )
17147                })?
17148                .await?;
17149            anyhow::Ok(navigated)
17150        })
17151    }
17152
17153    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17154        let selection = self.selections.newest_anchor();
17155        let head = selection.head();
17156        let tail = selection.tail();
17157
17158        let Some((buffer, start_position)) =
17159            self.buffer.read(cx).text_anchor_for_position(head, cx)
17160        else {
17161            return;
17162        };
17163
17164        let end_position = if head != tail {
17165            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17166                return;
17167            };
17168            Some(pos)
17169        } else {
17170            None
17171        };
17172
17173        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17174            let url = if let Some(end_pos) = end_position {
17175                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17176            } else {
17177                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17178            };
17179
17180            if let Some(url) = url {
17181                cx.update(|window, cx| {
17182                    if parse_zed_link(&url, cx).is_some() {
17183                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17184                    } else {
17185                        cx.open_url(&url);
17186                    }
17187                })?;
17188            }
17189
17190            anyhow::Ok(())
17191        });
17192
17193        url_finder.detach();
17194    }
17195
17196    pub fn open_selected_filename(
17197        &mut self,
17198        _: &OpenSelectedFilename,
17199        window: &mut Window,
17200        cx: &mut Context<Self>,
17201    ) {
17202        let Some(workspace) = self.workspace() else {
17203            return;
17204        };
17205
17206        let position = self.selections.newest_anchor().head();
17207
17208        let Some((buffer, buffer_position)) =
17209            self.buffer.read(cx).text_anchor_for_position(position, cx)
17210        else {
17211            return;
17212        };
17213
17214        let project = self.project.clone();
17215
17216        cx.spawn_in(window, async move |_, cx| {
17217            let result = find_file(&buffer, project, buffer_position, cx).await;
17218
17219            if let Some((_, path)) = result {
17220                workspace
17221                    .update_in(cx, |workspace, window, cx| {
17222                        workspace.open_resolved_path(path, window, cx)
17223                    })?
17224                    .await?;
17225            }
17226            anyhow::Ok(())
17227        })
17228        .detach();
17229    }
17230
17231    pub(crate) fn navigate_to_hover_links(
17232        &mut self,
17233        kind: Option<GotoDefinitionKind>,
17234        definitions: Vec<HoverLink>,
17235        split: bool,
17236        window: &mut Window,
17237        cx: &mut Context<Editor>,
17238    ) -> Task<Result<Navigated>> {
17239        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17240        let mut first_url_or_file = None;
17241        let definitions: Vec<_> = definitions
17242            .into_iter()
17243            .filter_map(|def| match def {
17244                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17245                HoverLink::InlayHint(lsp_location, server_id) => {
17246                    let computation =
17247                        self.compute_target_location(lsp_location, server_id, window, cx);
17248                    Some(cx.background_spawn(computation))
17249                }
17250                HoverLink::Url(url) => {
17251                    first_url_or_file = Some(Either::Left(url));
17252                    None
17253                }
17254                HoverLink::File(path) => {
17255                    first_url_or_file = Some(Either::Right(path));
17256                    None
17257                }
17258            })
17259            .collect();
17260
17261        let workspace = self.workspace();
17262
17263        cx.spawn_in(window, async move |editor, cx| {
17264            let locations: Vec<Location> = future::join_all(definitions)
17265                .await
17266                .into_iter()
17267                .filter_map(|location| location.transpose())
17268                .collect::<Result<_>>()
17269                .context("location tasks")?;
17270            let mut locations = cx.update(|_, cx| {
17271                locations
17272                    .into_iter()
17273                    .map(|location| {
17274                        let buffer = location.buffer.read(cx);
17275                        (location.buffer, location.range.to_point(buffer))
17276                    })
17277                    .into_group_map()
17278            })?;
17279            let mut num_locations = 0;
17280            for ranges in locations.values_mut() {
17281                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17282                ranges.dedup();
17283                num_locations += ranges.len();
17284            }
17285
17286            if num_locations > 1 {
17287                let tab_kind = match kind {
17288                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17289                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17290                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17291                    Some(GotoDefinitionKind::Type) => "Types",
17292                };
17293                let title = editor
17294                    .update_in(cx, |_, _, cx| {
17295                        let target = locations
17296                            .iter()
17297                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17298                            .map(|(buffer, location)| {
17299                                buffer
17300                                    .read(cx)
17301                                    .text_for_range(location.clone())
17302                                    .collect::<String>()
17303                            })
17304                            .filter(|text| !text.contains('\n'))
17305                            .unique()
17306                            .take(3)
17307                            .join(", ");
17308                        if target.is_empty() {
17309                            tab_kind.to_owned()
17310                        } else {
17311                            format!("{tab_kind} for {target}")
17312                        }
17313                    })
17314                    .context("buffer title")?;
17315
17316                let Some(workspace) = workspace else {
17317                    return Ok(Navigated::No);
17318                };
17319
17320                let opened = workspace
17321                    .update_in(cx, |workspace, window, cx| {
17322                        let allow_preview = PreviewTabsSettings::get_global(cx)
17323                            .enable_preview_multibuffer_from_code_navigation;
17324                        Self::open_locations_in_multibuffer(
17325                            workspace,
17326                            locations,
17327                            title,
17328                            split,
17329                            allow_preview,
17330                            MultibufferSelectionMode::First,
17331                            window,
17332                            cx,
17333                        )
17334                    })
17335                    .is_ok();
17336
17337                anyhow::Ok(Navigated::from_bool(opened))
17338            } else if num_locations == 0 {
17339                // If there is one url or file, open it directly
17340                match first_url_or_file {
17341                    Some(Either::Left(url)) => {
17342                        cx.update(|window, cx| {
17343                            if parse_zed_link(&url, cx).is_some() {
17344                                window
17345                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17346                            } else {
17347                                cx.open_url(&url);
17348                            }
17349                        })?;
17350                        Ok(Navigated::Yes)
17351                    }
17352                    Some(Either::Right(path)) => {
17353                        // TODO(andrew): respect preview tab settings
17354                        //               `enable_keep_preview_on_code_navigation` and
17355                        //               `enable_preview_file_from_code_navigation`
17356                        let Some(workspace) = workspace else {
17357                            return Ok(Navigated::No);
17358                        };
17359                        workspace
17360                            .update_in(cx, |workspace, window, cx| {
17361                                workspace.open_resolved_path(path, window, cx)
17362                            })?
17363                            .await?;
17364                        Ok(Navigated::Yes)
17365                    }
17366                    None => Ok(Navigated::No),
17367                }
17368            } else {
17369                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17370                let target_range = target_ranges.first().unwrap().clone();
17371
17372                editor.update_in(cx, |editor, window, cx| {
17373                    let range = target_range.to_point(target_buffer.read(cx));
17374                    let range = editor.range_for_match(&range);
17375                    let range = collapse_multiline_range(range);
17376
17377                    if !split
17378                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17379                    {
17380                        editor.go_to_singleton_buffer_range(range, window, cx);
17381                    } else {
17382                        let Some(workspace) = workspace else {
17383                            return Navigated::No;
17384                        };
17385                        let pane = workspace.read(cx).active_pane().clone();
17386                        window.defer(cx, move |window, cx| {
17387                            let target_editor: Entity<Self> =
17388                                workspace.update(cx, |workspace, cx| {
17389                                    let pane = if split {
17390                                        workspace.adjacent_pane(window, cx)
17391                                    } else {
17392                                        workspace.active_pane().clone()
17393                                    };
17394
17395                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17396                                    let keep_old_preview = preview_tabs_settings
17397                                        .enable_keep_preview_on_code_navigation;
17398                                    let allow_new_preview = preview_tabs_settings
17399                                        .enable_preview_file_from_code_navigation;
17400
17401                                    workspace.open_project_item(
17402                                        pane,
17403                                        target_buffer.clone(),
17404                                        true,
17405                                        true,
17406                                        keep_old_preview,
17407                                        allow_new_preview,
17408                                        window,
17409                                        cx,
17410                                    )
17411                                });
17412                            target_editor.update(cx, |target_editor, cx| {
17413                                // When selecting a definition in a different buffer, disable the nav history
17414                                // to avoid creating a history entry at the previous cursor location.
17415                                pane.update(cx, |pane, _| pane.disable_history());
17416                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17417                                pane.update(cx, |pane, _| pane.enable_history());
17418                            });
17419                        });
17420                    }
17421                    Navigated::Yes
17422                })
17423            }
17424        })
17425    }
17426
17427    fn compute_target_location(
17428        &self,
17429        lsp_location: lsp::Location,
17430        server_id: LanguageServerId,
17431        window: &mut Window,
17432        cx: &mut Context<Self>,
17433    ) -> Task<anyhow::Result<Option<Location>>> {
17434        let Some(project) = self.project.clone() else {
17435            return Task::ready(Ok(None));
17436        };
17437
17438        cx.spawn_in(window, async move |editor, cx| {
17439            let location_task = editor.update(cx, |_, cx| {
17440                project.update(cx, |project, cx| {
17441                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17442                })
17443            })?;
17444            let location = Some({
17445                let target_buffer_handle = location_task.await.context("open local buffer")?;
17446                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17447                    let target_start = target_buffer
17448                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17449                    let target_end = target_buffer
17450                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17451                    target_buffer.anchor_after(target_start)
17452                        ..target_buffer.anchor_before(target_end)
17453                })?;
17454                Location {
17455                    buffer: target_buffer_handle,
17456                    range,
17457                }
17458            });
17459            Ok(location)
17460        })
17461    }
17462
17463    fn go_to_next_reference(
17464        &mut self,
17465        _: &GoToNextReference,
17466        window: &mut Window,
17467        cx: &mut Context<Self>,
17468    ) {
17469        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17470        if let Some(task) = task {
17471            task.detach();
17472        };
17473    }
17474
17475    fn go_to_prev_reference(
17476        &mut self,
17477        _: &GoToPreviousReference,
17478        window: &mut Window,
17479        cx: &mut Context<Self>,
17480    ) {
17481        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17482        if let Some(task) = task {
17483            task.detach();
17484        };
17485    }
17486
17487    pub fn go_to_reference_before_or_after_position(
17488        &mut self,
17489        direction: Direction,
17490        count: usize,
17491        window: &mut Window,
17492        cx: &mut Context<Self>,
17493    ) -> Option<Task<Result<()>>> {
17494        let selection = self.selections.newest_anchor();
17495        let head = selection.head();
17496
17497        let multi_buffer = self.buffer.read(cx);
17498
17499        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17500        let workspace = self.workspace()?;
17501        let project = workspace.read(cx).project().clone();
17502        let references =
17503            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17504        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17505            let Some(locations) = references.await? else {
17506                return Ok(());
17507            };
17508
17509            if locations.is_empty() {
17510                // totally normal - the cursor may be on something which is not
17511                // a symbol (e.g. a keyword)
17512                log::info!("no references found under cursor");
17513                return Ok(());
17514            }
17515
17516            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17517
17518            let (locations, current_location_index) =
17519                multi_buffer.update(cx, |multi_buffer, cx| {
17520                    let mut locations = locations
17521                        .into_iter()
17522                        .filter_map(|loc| {
17523                            let start = multi_buffer.buffer_anchor_to_anchor(
17524                                &loc.buffer,
17525                                loc.range.start,
17526                                cx,
17527                            )?;
17528                            let end = multi_buffer.buffer_anchor_to_anchor(
17529                                &loc.buffer,
17530                                loc.range.end,
17531                                cx,
17532                            )?;
17533                            Some(start..end)
17534                        })
17535                        .collect::<Vec<_>>();
17536
17537                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17538                    // There is an O(n) implementation, but given this list will be
17539                    // small (usually <100 items), the extra O(log(n)) factor isn't
17540                    // worth the (surprisingly large amount of) extra complexity.
17541                    locations
17542                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17543
17544                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17545
17546                    let current_location_index = locations.iter().position(|loc| {
17547                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17548                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17549                    });
17550
17551                    (locations, current_location_index)
17552                })?;
17553
17554            let Some(current_location_index) = current_location_index else {
17555                // This indicates something has gone wrong, because we already
17556                // handle the "no references" case above
17557                log::error!(
17558                    "failed to find current reference under cursor. Total references: {}",
17559                    locations.len()
17560                );
17561                return Ok(());
17562            };
17563
17564            let destination_location_index = match direction {
17565                Direction::Next => (current_location_index + count) % locations.len(),
17566                Direction::Prev => {
17567                    (current_location_index + locations.len() - count % locations.len())
17568                        % locations.len()
17569                }
17570            };
17571
17572            // TODO(cameron): is this needed?
17573            // the thinking is to avoid "jumping to the current location" (avoid
17574            // polluting "jumplist" in vim terms)
17575            if current_location_index == destination_location_index {
17576                return Ok(());
17577            }
17578
17579            let Range { start, end } = locations[destination_location_index];
17580
17581            editor.update_in(cx, |editor, window, cx| {
17582                let effects = SelectionEffects::default();
17583
17584                editor.unfold_ranges(&[start..end], false, false, cx);
17585                editor.change_selections(effects, window, cx, |s| {
17586                    s.select_ranges([start..start]);
17587                });
17588            })?;
17589
17590            Ok(())
17591        }))
17592    }
17593
17594    pub fn find_all_references(
17595        &mut self,
17596        action: &FindAllReferences,
17597        window: &mut Window,
17598        cx: &mut Context<Self>,
17599    ) -> Option<Task<Result<Navigated>>> {
17600        let always_open_multibuffer = action.always_open_multibuffer;
17601        let selection = self.selections.newest_anchor();
17602        let multi_buffer = self.buffer.read(cx);
17603        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17604        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17605        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17606        let head = selection_offset.head();
17607
17608        let head_anchor = multi_buffer_snapshot.anchor_at(
17609            head,
17610            if head < selection_offset.tail() {
17611                Bias::Right
17612            } else {
17613                Bias::Left
17614            },
17615        );
17616
17617        match self
17618            .find_all_references_task_sources
17619            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17620        {
17621            Ok(_) => {
17622                log::info!(
17623                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17624                );
17625                return None;
17626            }
17627            Err(i) => {
17628                self.find_all_references_task_sources.insert(i, head_anchor);
17629            }
17630        }
17631
17632        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17633        let workspace = self.workspace()?;
17634        let project = workspace.read(cx).project().clone();
17635        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17636        Some(cx.spawn_in(window, async move |editor, cx| {
17637            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17638                if let Ok(i) = editor
17639                    .find_all_references_task_sources
17640                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17641                {
17642                    editor.find_all_references_task_sources.remove(i);
17643                }
17644            });
17645
17646            let Some(locations) = references.await? else {
17647                return anyhow::Ok(Navigated::No);
17648            };
17649            let mut locations = cx.update(|_, cx| {
17650                locations
17651                    .into_iter()
17652                    .map(|location| {
17653                        let buffer = location.buffer.read(cx);
17654                        (location.buffer, location.range.to_point(buffer))
17655                    })
17656                    // if special-casing the single-match case, remove ranges
17657                    // that intersect current selection
17658                    .filter(|(location_buffer, location)| {
17659                        if always_open_multibuffer || &buffer != location_buffer {
17660                            return true;
17661                        }
17662
17663                        !location.contains_inclusive(&selection_point.range())
17664                    })
17665                    .into_group_map()
17666            })?;
17667            if locations.is_empty() {
17668                return anyhow::Ok(Navigated::No);
17669            }
17670            for ranges in locations.values_mut() {
17671                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17672                ranges.dedup();
17673            }
17674            let mut num_locations = 0;
17675            for ranges in locations.values_mut() {
17676                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17677                ranges.dedup();
17678                num_locations += ranges.len();
17679            }
17680
17681            if num_locations == 1 && !always_open_multibuffer {
17682                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17683                let target_range = target_ranges.first().unwrap().clone();
17684
17685                return editor.update_in(cx, |editor, window, cx| {
17686                    let range = target_range.to_point(target_buffer.read(cx));
17687                    let range = editor.range_for_match(&range);
17688                    let range = range.start..range.start;
17689
17690                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17691                        editor.go_to_singleton_buffer_range(range, window, cx);
17692                    } else {
17693                        let pane = workspace.read(cx).active_pane().clone();
17694                        window.defer(cx, move |window, cx| {
17695                            let target_editor: Entity<Self> =
17696                                workspace.update(cx, |workspace, cx| {
17697                                    let pane = workspace.active_pane().clone();
17698
17699                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17700                                    let keep_old_preview = preview_tabs_settings
17701                                        .enable_keep_preview_on_code_navigation;
17702                                    let allow_new_preview = preview_tabs_settings
17703                                        .enable_preview_file_from_code_navigation;
17704
17705                                    workspace.open_project_item(
17706                                        pane,
17707                                        target_buffer.clone(),
17708                                        true,
17709                                        true,
17710                                        keep_old_preview,
17711                                        allow_new_preview,
17712                                        window,
17713                                        cx,
17714                                    )
17715                                });
17716                            target_editor.update(cx, |target_editor, cx| {
17717                                // When selecting a definition in a different buffer, disable the nav history
17718                                // to avoid creating a history entry at the previous cursor location.
17719                                pane.update(cx, |pane, _| pane.disable_history());
17720                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17721                                pane.update(cx, |pane, _| pane.enable_history());
17722                            });
17723                        });
17724                    }
17725                    Navigated::No
17726                });
17727            }
17728
17729            workspace.update_in(cx, |workspace, window, cx| {
17730                let target = locations
17731                    .iter()
17732                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17733                    .map(|(buffer, location)| {
17734                        buffer
17735                            .read(cx)
17736                            .text_for_range(location.clone())
17737                            .collect::<String>()
17738                    })
17739                    .filter(|text| !text.contains('\n'))
17740                    .unique()
17741                    .take(3)
17742                    .join(", ");
17743                let title = if target.is_empty() {
17744                    "References".to_owned()
17745                } else {
17746                    format!("References to {target}")
17747                };
17748                let allow_preview = PreviewTabsSettings::get_global(cx)
17749                    .enable_preview_multibuffer_from_code_navigation;
17750                Self::open_locations_in_multibuffer(
17751                    workspace,
17752                    locations,
17753                    title,
17754                    false,
17755                    allow_preview,
17756                    MultibufferSelectionMode::First,
17757                    window,
17758                    cx,
17759                );
17760                Navigated::Yes
17761            })
17762        }))
17763    }
17764
17765    /// Opens a multibuffer with the given project locations in it.
17766    pub fn open_locations_in_multibuffer(
17767        workspace: &mut Workspace,
17768        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17769        title: String,
17770        split: bool,
17771        allow_preview: bool,
17772        multibuffer_selection_mode: MultibufferSelectionMode,
17773        window: &mut Window,
17774        cx: &mut Context<Workspace>,
17775    ) {
17776        if locations.is_empty() {
17777            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17778            return;
17779        }
17780
17781        let capability = workspace.project().read(cx).capability();
17782        let mut ranges = <Vec<Range<Anchor>>>::new();
17783
17784        // a key to find existing multibuffer editors with the same set of locations
17785        // to prevent us from opening more and more multibuffer tabs for searches and the like
17786        let mut key = (title.clone(), vec![]);
17787        let excerpt_buffer = cx.new(|cx| {
17788            let key = &mut key.1;
17789            let mut multibuffer = MultiBuffer::new(capability);
17790            for (buffer, mut ranges_for_buffer) in locations {
17791                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17792                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17793                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17794                    PathKey::for_buffer(&buffer, cx),
17795                    buffer.clone(),
17796                    ranges_for_buffer,
17797                    multibuffer_context_lines(cx),
17798                    cx,
17799                );
17800                ranges.extend(new_ranges)
17801            }
17802
17803            multibuffer.with_title(title)
17804        });
17805        let existing = workspace.active_pane().update(cx, |pane, cx| {
17806            pane.items()
17807                .filter_map(|item| item.downcast::<Editor>())
17808                .find(|editor| {
17809                    editor
17810                        .read(cx)
17811                        .lookup_key
17812                        .as_ref()
17813                        .and_then(|it| {
17814                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17815                        })
17816                        .is_some_and(|it| *it == key)
17817                })
17818        });
17819        let was_existing = existing.is_some();
17820        let editor = existing.unwrap_or_else(|| {
17821            cx.new(|cx| {
17822                let mut editor = Editor::for_multibuffer(
17823                    excerpt_buffer,
17824                    Some(workspace.project().clone()),
17825                    window,
17826                    cx,
17827                );
17828                editor.lookup_key = Some(Box::new(key));
17829                editor
17830            })
17831        });
17832        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17833            MultibufferSelectionMode::First => {
17834                if let Some(first_range) = ranges.first() {
17835                    editor.change_selections(
17836                        SelectionEffects::no_scroll(),
17837                        window,
17838                        cx,
17839                        |selections| {
17840                            selections.clear_disjoint();
17841                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17842                        },
17843                    );
17844                }
17845                editor.highlight_background::<Self>(
17846                    &ranges,
17847                    |_, theme| theme.colors().editor_highlighted_line_background,
17848                    cx,
17849                );
17850            }
17851            MultibufferSelectionMode::All => {
17852                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17853                    selections.clear_disjoint();
17854                    selections.select_anchor_ranges(ranges);
17855                });
17856            }
17857        });
17858
17859        let item = Box::new(editor);
17860
17861        let pane = if split {
17862            workspace.adjacent_pane(window, cx)
17863        } else {
17864            workspace.active_pane().clone()
17865        };
17866        let activate_pane = split;
17867
17868        let mut destination_index = None;
17869        pane.update(cx, |pane, cx| {
17870            if allow_preview && !was_existing {
17871                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
17872            }
17873            if was_existing && !allow_preview {
17874                pane.unpreview_item_if_preview(item.item_id());
17875            }
17876            pane.add_item(item, activate_pane, true, destination_index, window, cx);
17877        });
17878    }
17879
17880    pub fn rename(
17881        &mut self,
17882        _: &Rename,
17883        window: &mut Window,
17884        cx: &mut Context<Self>,
17885    ) -> Option<Task<Result<()>>> {
17886        use language::ToOffset as _;
17887
17888        let provider = self.semantics_provider.clone()?;
17889        let selection = self.selections.newest_anchor().clone();
17890        let (cursor_buffer, cursor_buffer_position) = self
17891            .buffer
17892            .read(cx)
17893            .text_anchor_for_position(selection.head(), cx)?;
17894        let (tail_buffer, cursor_buffer_position_end) = self
17895            .buffer
17896            .read(cx)
17897            .text_anchor_for_position(selection.tail(), cx)?;
17898        if tail_buffer != cursor_buffer {
17899            return None;
17900        }
17901
17902        let snapshot = cursor_buffer.read(cx).snapshot();
17903        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17904        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17905        let prepare_rename = provider
17906            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17907            .unwrap_or_else(|| Task::ready(Ok(None)));
17908        drop(snapshot);
17909
17910        Some(cx.spawn_in(window, async move |this, cx| {
17911            let rename_range = if let Some(range) = prepare_rename.await? {
17912                Some(range)
17913            } else {
17914                this.update(cx, |this, cx| {
17915                    let buffer = this.buffer.read(cx).snapshot(cx);
17916                    let mut buffer_highlights = this
17917                        .document_highlights_for_position(selection.head(), &buffer)
17918                        .filter(|highlight| {
17919                            highlight.start.excerpt_id == selection.head().excerpt_id
17920                                && highlight.end.excerpt_id == selection.head().excerpt_id
17921                        });
17922                    buffer_highlights
17923                        .next()
17924                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17925                })?
17926            };
17927            if let Some(rename_range) = rename_range {
17928                this.update_in(cx, |this, window, cx| {
17929                    let snapshot = cursor_buffer.read(cx).snapshot();
17930                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17931                    let cursor_offset_in_rename_range =
17932                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17933                    let cursor_offset_in_rename_range_end =
17934                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17935
17936                    this.take_rename(false, window, cx);
17937                    let buffer = this.buffer.read(cx).read(cx);
17938                    let cursor_offset = selection.head().to_offset(&buffer);
17939                    let rename_start =
17940                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17941                    let rename_end = rename_start + rename_buffer_range.len();
17942                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17943                    let mut old_highlight_id = None;
17944                    let old_name: Arc<str> = buffer
17945                        .chunks(rename_start..rename_end, true)
17946                        .map(|chunk| {
17947                            if old_highlight_id.is_none() {
17948                                old_highlight_id = chunk.syntax_highlight_id;
17949                            }
17950                            chunk.text
17951                        })
17952                        .collect::<String>()
17953                        .into();
17954
17955                    drop(buffer);
17956
17957                    // Position the selection in the rename editor so that it matches the current selection.
17958                    this.show_local_selections = false;
17959                    let rename_editor = cx.new(|cx| {
17960                        let mut editor = Editor::single_line(window, cx);
17961                        editor.buffer.update(cx, |buffer, cx| {
17962                            buffer.edit(
17963                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17964                                None,
17965                                cx,
17966                            )
17967                        });
17968                        let cursor_offset_in_rename_range =
17969                            MultiBufferOffset(cursor_offset_in_rename_range);
17970                        let cursor_offset_in_rename_range_end =
17971                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17972                        let rename_selection_range = match cursor_offset_in_rename_range
17973                            .cmp(&cursor_offset_in_rename_range_end)
17974                        {
17975                            Ordering::Equal => {
17976                                editor.select_all(&SelectAll, window, cx);
17977                                return editor;
17978                            }
17979                            Ordering::Less => {
17980                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17981                            }
17982                            Ordering::Greater => {
17983                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17984                            }
17985                        };
17986                        if rename_selection_range.end.0 > old_name.len() {
17987                            editor.select_all(&SelectAll, window, cx);
17988                        } else {
17989                            editor.change_selections(Default::default(), window, cx, |s| {
17990                                s.select_ranges([rename_selection_range]);
17991                            });
17992                        }
17993                        editor
17994                    });
17995                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17996                        if e == &EditorEvent::Focused {
17997                            cx.emit(EditorEvent::FocusedIn)
17998                        }
17999                    })
18000                    .detach();
18001
18002                    let write_highlights =
18003                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18004                    let read_highlights =
18005                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18006                    let ranges = write_highlights
18007                        .iter()
18008                        .flat_map(|(_, ranges)| ranges.iter())
18009                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18010                        .cloned()
18011                        .collect();
18012
18013                    this.highlight_text::<Rename>(
18014                        ranges,
18015                        HighlightStyle {
18016                            fade_out: Some(0.6),
18017                            ..Default::default()
18018                        },
18019                        cx,
18020                    );
18021                    let rename_focus_handle = rename_editor.focus_handle(cx);
18022                    window.focus(&rename_focus_handle, cx);
18023                    let block_id = this.insert_blocks(
18024                        [BlockProperties {
18025                            style: BlockStyle::Flex,
18026                            placement: BlockPlacement::Below(range.start),
18027                            height: Some(1),
18028                            render: Arc::new({
18029                                let rename_editor = rename_editor.clone();
18030                                move |cx: &mut BlockContext| {
18031                                    let mut text_style = cx.editor_style.text.clone();
18032                                    if let Some(highlight_style) = old_highlight_id
18033                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18034                                    {
18035                                        text_style = text_style.highlight(highlight_style);
18036                                    }
18037                                    div()
18038                                        .block_mouse_except_scroll()
18039                                        .pl(cx.anchor_x)
18040                                        .child(EditorElement::new(
18041                                            &rename_editor,
18042                                            EditorStyle {
18043                                                background: cx.theme().system().transparent,
18044                                                local_player: cx.editor_style.local_player,
18045                                                text: text_style,
18046                                                scrollbar_width: cx.editor_style.scrollbar_width,
18047                                                syntax: cx.editor_style.syntax.clone(),
18048                                                status: cx.editor_style.status.clone(),
18049                                                inlay_hints_style: HighlightStyle {
18050                                                    font_weight: Some(FontWeight::BOLD),
18051                                                    ..make_inlay_hints_style(cx.app)
18052                                                },
18053                                                edit_prediction_styles: make_suggestion_styles(
18054                                                    cx.app,
18055                                                ),
18056                                                ..EditorStyle::default()
18057                                            },
18058                                        ))
18059                                        .into_any_element()
18060                                }
18061                            }),
18062                            priority: 0,
18063                        }],
18064                        Some(Autoscroll::fit()),
18065                        cx,
18066                    )[0];
18067                    this.pending_rename = Some(RenameState {
18068                        range,
18069                        old_name,
18070                        editor: rename_editor,
18071                        block_id,
18072                    });
18073                })?;
18074            }
18075
18076            Ok(())
18077        }))
18078    }
18079
18080    pub fn confirm_rename(
18081        &mut self,
18082        _: &ConfirmRename,
18083        window: &mut Window,
18084        cx: &mut Context<Self>,
18085    ) -> Option<Task<Result<()>>> {
18086        let rename = self.take_rename(false, window, cx)?;
18087        let workspace = self.workspace()?.downgrade();
18088        let (buffer, start) = self
18089            .buffer
18090            .read(cx)
18091            .text_anchor_for_position(rename.range.start, cx)?;
18092        let (end_buffer, _) = self
18093            .buffer
18094            .read(cx)
18095            .text_anchor_for_position(rename.range.end, cx)?;
18096        if buffer != end_buffer {
18097            return None;
18098        }
18099
18100        let old_name = rename.old_name;
18101        let new_name = rename.editor.read(cx).text(cx);
18102
18103        let rename = self.semantics_provider.as_ref()?.perform_rename(
18104            &buffer,
18105            start,
18106            new_name.clone(),
18107            cx,
18108        )?;
18109
18110        Some(cx.spawn_in(window, async move |editor, cx| {
18111            let project_transaction = rename.await?;
18112            Self::open_project_transaction(
18113                &editor,
18114                workspace,
18115                project_transaction,
18116                format!("Rename: {}{}", old_name, new_name),
18117                cx,
18118            )
18119            .await?;
18120
18121            editor.update(cx, |editor, cx| {
18122                editor.refresh_document_highlights(cx);
18123            })?;
18124            Ok(())
18125        }))
18126    }
18127
18128    fn take_rename(
18129        &mut self,
18130        moving_cursor: bool,
18131        window: &mut Window,
18132        cx: &mut Context<Self>,
18133    ) -> Option<RenameState> {
18134        let rename = self.pending_rename.take()?;
18135        if rename.editor.focus_handle(cx).is_focused(window) {
18136            window.focus(&self.focus_handle, cx);
18137        }
18138
18139        self.remove_blocks(
18140            [rename.block_id].into_iter().collect(),
18141            Some(Autoscroll::fit()),
18142            cx,
18143        );
18144        self.clear_highlights::<Rename>(cx);
18145        self.show_local_selections = true;
18146
18147        if moving_cursor {
18148            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18149                editor
18150                    .selections
18151                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18152                    .head()
18153            });
18154
18155            // Update the selection to match the position of the selection inside
18156            // the rename editor.
18157            let snapshot = self.buffer.read(cx).read(cx);
18158            let rename_range = rename.range.to_offset(&snapshot);
18159            let cursor_in_editor = snapshot
18160                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18161                .min(rename_range.end);
18162            drop(snapshot);
18163
18164            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18165                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18166            });
18167        } else {
18168            self.refresh_document_highlights(cx);
18169        }
18170
18171        Some(rename)
18172    }
18173
18174    pub fn pending_rename(&self) -> Option<&RenameState> {
18175        self.pending_rename.as_ref()
18176    }
18177
18178    fn format(
18179        &mut self,
18180        _: &Format,
18181        window: &mut Window,
18182        cx: &mut Context<Self>,
18183    ) -> Option<Task<Result<()>>> {
18184        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18185
18186        let project = match &self.project {
18187            Some(project) => project.clone(),
18188            None => return None,
18189        };
18190
18191        Some(self.perform_format(
18192            project,
18193            FormatTrigger::Manual,
18194            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18195            window,
18196            cx,
18197        ))
18198    }
18199
18200    fn format_selections(
18201        &mut self,
18202        _: &FormatSelections,
18203        window: &mut Window,
18204        cx: &mut Context<Self>,
18205    ) -> Option<Task<Result<()>>> {
18206        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18207
18208        let project = match &self.project {
18209            Some(project) => project.clone(),
18210            None => return None,
18211        };
18212
18213        let ranges = self
18214            .selections
18215            .all_adjusted(&self.display_snapshot(cx))
18216            .into_iter()
18217            .map(|selection| selection.range())
18218            .collect_vec();
18219
18220        Some(self.perform_format(
18221            project,
18222            FormatTrigger::Manual,
18223            FormatTarget::Ranges(ranges),
18224            window,
18225            cx,
18226        ))
18227    }
18228
18229    fn perform_format(
18230        &mut self,
18231        project: Entity<Project>,
18232        trigger: FormatTrigger,
18233        target: FormatTarget,
18234        window: &mut Window,
18235        cx: &mut Context<Self>,
18236    ) -> Task<Result<()>> {
18237        let buffer = self.buffer.clone();
18238        let (buffers, target) = match target {
18239            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18240            FormatTarget::Ranges(selection_ranges) => {
18241                let multi_buffer = buffer.read(cx);
18242                let snapshot = multi_buffer.read(cx);
18243                let mut buffers = HashSet::default();
18244                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18245                    BTreeMap::new();
18246                for selection_range in selection_ranges {
18247                    for (buffer, buffer_range, _) in
18248                        snapshot.range_to_buffer_ranges(selection_range)
18249                    {
18250                        let buffer_id = buffer.remote_id();
18251                        let start = buffer.anchor_before(buffer_range.start);
18252                        let end = buffer.anchor_after(buffer_range.end);
18253                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18254                        buffer_id_to_ranges
18255                            .entry(buffer_id)
18256                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18257                            .or_insert_with(|| vec![start..end]);
18258                    }
18259                }
18260                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18261            }
18262        };
18263
18264        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18265        let selections_prev = transaction_id_prev
18266            .and_then(|transaction_id_prev| {
18267                // default to selections as they were after the last edit, if we have them,
18268                // instead of how they are now.
18269                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18270                // will take you back to where you made the last edit, instead of staying where you scrolled
18271                self.selection_history
18272                    .transaction(transaction_id_prev)
18273                    .map(|t| t.0.clone())
18274            })
18275            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18276
18277        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18278        let format = project.update(cx, |project, cx| {
18279            project.format(buffers, target, true, trigger, cx)
18280        });
18281
18282        cx.spawn_in(window, async move |editor, cx| {
18283            let transaction = futures::select_biased! {
18284                transaction = format.log_err().fuse() => transaction,
18285                () = timeout => {
18286                    log::warn!("timed out waiting for formatting");
18287                    None
18288                }
18289            };
18290
18291            buffer
18292                .update(cx, |buffer, cx| {
18293                    if let Some(transaction) = transaction
18294                        && !buffer.is_singleton()
18295                    {
18296                        buffer.push_transaction(&transaction.0, cx);
18297                    }
18298                    cx.notify();
18299                })
18300                .ok();
18301
18302            if let Some(transaction_id_now) =
18303                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18304            {
18305                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18306                if has_new_transaction {
18307                    _ = editor.update(cx, |editor, _| {
18308                        editor
18309                            .selection_history
18310                            .insert_transaction(transaction_id_now, selections_prev);
18311                    });
18312                }
18313            }
18314
18315            Ok(())
18316        })
18317    }
18318
18319    fn organize_imports(
18320        &mut self,
18321        _: &OrganizeImports,
18322        window: &mut Window,
18323        cx: &mut Context<Self>,
18324    ) -> Option<Task<Result<()>>> {
18325        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18326        let project = match &self.project {
18327            Some(project) => project.clone(),
18328            None => return None,
18329        };
18330        Some(self.perform_code_action_kind(
18331            project,
18332            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18333            window,
18334            cx,
18335        ))
18336    }
18337
18338    fn perform_code_action_kind(
18339        &mut self,
18340        project: Entity<Project>,
18341        kind: CodeActionKind,
18342        window: &mut Window,
18343        cx: &mut Context<Self>,
18344    ) -> Task<Result<()>> {
18345        let buffer = self.buffer.clone();
18346        let buffers = buffer.read(cx).all_buffers();
18347        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18348        let apply_action = project.update(cx, |project, cx| {
18349            project.apply_code_action_kind(buffers, kind, true, cx)
18350        });
18351        cx.spawn_in(window, async move |_, cx| {
18352            let transaction = futures::select_biased! {
18353                () = timeout => {
18354                    log::warn!("timed out waiting for executing code action");
18355                    None
18356                }
18357                transaction = apply_action.log_err().fuse() => transaction,
18358            };
18359            buffer
18360                .update(cx, |buffer, cx| {
18361                    // check if we need this
18362                    if let Some(transaction) = transaction
18363                        && !buffer.is_singleton()
18364                    {
18365                        buffer.push_transaction(&transaction.0, cx);
18366                    }
18367                    cx.notify();
18368                })
18369                .ok();
18370            Ok(())
18371        })
18372    }
18373
18374    pub fn restart_language_server(
18375        &mut self,
18376        _: &RestartLanguageServer,
18377        _: &mut Window,
18378        cx: &mut Context<Self>,
18379    ) {
18380        if let Some(project) = self.project.clone() {
18381            self.buffer.update(cx, |multi_buffer, cx| {
18382                project.update(cx, |project, cx| {
18383                    project.restart_language_servers_for_buffers(
18384                        multi_buffer.all_buffers().into_iter().collect(),
18385                        HashSet::default(),
18386                        cx,
18387                    );
18388                });
18389            })
18390        }
18391    }
18392
18393    pub fn stop_language_server(
18394        &mut self,
18395        _: &StopLanguageServer,
18396        _: &mut Window,
18397        cx: &mut Context<Self>,
18398    ) {
18399        if let Some(project) = self.project.clone() {
18400            self.buffer.update(cx, |multi_buffer, cx| {
18401                project.update(cx, |project, cx| {
18402                    project.stop_language_servers_for_buffers(
18403                        multi_buffer.all_buffers().into_iter().collect(),
18404                        HashSet::default(),
18405                        cx,
18406                    );
18407                });
18408            });
18409            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18410        }
18411    }
18412
18413    fn cancel_language_server_work(
18414        workspace: &mut Workspace,
18415        _: &actions::CancelLanguageServerWork,
18416        _: &mut Window,
18417        cx: &mut Context<Workspace>,
18418    ) {
18419        let project = workspace.project();
18420        let buffers = workspace
18421            .active_item(cx)
18422            .and_then(|item| item.act_as::<Editor>(cx))
18423            .map_or(HashSet::default(), |editor| {
18424                editor.read(cx).buffer.read(cx).all_buffers()
18425            });
18426        project.update(cx, |project, cx| {
18427            project.cancel_language_server_work_for_buffers(buffers, cx);
18428        });
18429    }
18430
18431    fn show_character_palette(
18432        &mut self,
18433        _: &ShowCharacterPalette,
18434        window: &mut Window,
18435        _: &mut Context<Self>,
18436    ) {
18437        window.show_character_palette();
18438    }
18439
18440    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18441        if !self.diagnostics_enabled() {
18442            return;
18443        }
18444
18445        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18446            let buffer = self.buffer.read(cx).snapshot(cx);
18447            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18448            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18449            let is_valid = buffer
18450                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18451                .any(|entry| {
18452                    entry.diagnostic.is_primary
18453                        && !entry.range.is_empty()
18454                        && entry.range.start == primary_range_start
18455                        && entry.diagnostic.message == active_diagnostics.active_message
18456                });
18457
18458            if !is_valid {
18459                self.dismiss_diagnostics(cx);
18460            }
18461        }
18462    }
18463
18464    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18465        match &self.active_diagnostics {
18466            ActiveDiagnostic::Group(group) => Some(group),
18467            _ => None,
18468        }
18469    }
18470
18471    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18472        if !self.diagnostics_enabled() {
18473            return;
18474        }
18475        self.dismiss_diagnostics(cx);
18476        self.active_diagnostics = ActiveDiagnostic::All;
18477    }
18478
18479    fn activate_diagnostics(
18480        &mut self,
18481        buffer_id: BufferId,
18482        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18483        window: &mut Window,
18484        cx: &mut Context<Self>,
18485    ) {
18486        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18487            return;
18488        }
18489        self.dismiss_diagnostics(cx);
18490        let snapshot = self.snapshot(window, cx);
18491        let buffer = self.buffer.read(cx).snapshot(cx);
18492        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18493            return;
18494        };
18495
18496        let diagnostic_group = buffer
18497            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18498            .collect::<Vec<_>>();
18499
18500        let language_registry = self
18501            .project()
18502            .map(|project| project.read(cx).languages().clone());
18503
18504        let blocks = renderer.render_group(
18505            diagnostic_group,
18506            buffer_id,
18507            snapshot,
18508            cx.weak_entity(),
18509            language_registry,
18510            cx,
18511        );
18512
18513        let blocks = self.display_map.update(cx, |display_map, cx| {
18514            display_map.insert_blocks(blocks, cx).into_iter().collect()
18515        });
18516        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18517            active_range: buffer.anchor_before(diagnostic.range.start)
18518                ..buffer.anchor_after(diagnostic.range.end),
18519            active_message: diagnostic.diagnostic.message.clone(),
18520            group_id: diagnostic.diagnostic.group_id,
18521            blocks,
18522        });
18523        cx.notify();
18524    }
18525
18526    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18527        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18528            return;
18529        };
18530
18531        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18532        if let ActiveDiagnostic::Group(group) = prev {
18533            self.display_map.update(cx, |display_map, cx| {
18534                display_map.remove_blocks(group.blocks, cx);
18535            });
18536            cx.notify();
18537        }
18538    }
18539
18540    /// Disable inline diagnostics rendering for this editor.
18541    pub fn disable_inline_diagnostics(&mut self) {
18542        self.inline_diagnostics_enabled = false;
18543        self.inline_diagnostics_update = Task::ready(());
18544        self.inline_diagnostics.clear();
18545    }
18546
18547    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18548        self.diagnostics_enabled = false;
18549        self.dismiss_diagnostics(cx);
18550        self.inline_diagnostics_update = Task::ready(());
18551        self.inline_diagnostics.clear();
18552    }
18553
18554    pub fn disable_word_completions(&mut self) {
18555        self.word_completions_enabled = false;
18556    }
18557
18558    pub fn diagnostics_enabled(&self) -> bool {
18559        self.diagnostics_enabled && self.mode.is_full()
18560    }
18561
18562    pub fn inline_diagnostics_enabled(&self) -> bool {
18563        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18564    }
18565
18566    pub fn show_inline_diagnostics(&self) -> bool {
18567        self.show_inline_diagnostics
18568    }
18569
18570    pub fn toggle_inline_diagnostics(
18571        &mut self,
18572        _: &ToggleInlineDiagnostics,
18573        window: &mut Window,
18574        cx: &mut Context<Editor>,
18575    ) {
18576        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18577        self.refresh_inline_diagnostics(false, window, cx);
18578    }
18579
18580    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18581        self.diagnostics_max_severity = severity;
18582        self.display_map.update(cx, |display_map, _| {
18583            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18584        });
18585    }
18586
18587    pub fn toggle_diagnostics(
18588        &mut self,
18589        _: &ToggleDiagnostics,
18590        window: &mut Window,
18591        cx: &mut Context<Editor>,
18592    ) {
18593        if !self.diagnostics_enabled() {
18594            return;
18595        }
18596
18597        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18598            EditorSettings::get_global(cx)
18599                .diagnostics_max_severity
18600                .filter(|severity| severity != &DiagnosticSeverity::Off)
18601                .unwrap_or(DiagnosticSeverity::Hint)
18602        } else {
18603            DiagnosticSeverity::Off
18604        };
18605        self.set_max_diagnostics_severity(new_severity, cx);
18606        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18607            self.active_diagnostics = ActiveDiagnostic::None;
18608            self.inline_diagnostics_update = Task::ready(());
18609            self.inline_diagnostics.clear();
18610        } else {
18611            self.refresh_inline_diagnostics(false, window, cx);
18612        }
18613
18614        cx.notify();
18615    }
18616
18617    pub fn toggle_minimap(
18618        &mut self,
18619        _: &ToggleMinimap,
18620        window: &mut Window,
18621        cx: &mut Context<Editor>,
18622    ) {
18623        if self.supports_minimap(cx) {
18624            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18625        }
18626    }
18627
18628    fn refresh_inline_diagnostics(
18629        &mut self,
18630        debounce: bool,
18631        window: &mut Window,
18632        cx: &mut Context<Self>,
18633    ) {
18634        let max_severity = ProjectSettings::get_global(cx)
18635            .diagnostics
18636            .inline
18637            .max_severity
18638            .unwrap_or(self.diagnostics_max_severity);
18639
18640        if !self.inline_diagnostics_enabled()
18641            || !self.diagnostics_enabled()
18642            || !self.show_inline_diagnostics
18643            || max_severity == DiagnosticSeverity::Off
18644        {
18645            self.inline_diagnostics_update = Task::ready(());
18646            self.inline_diagnostics.clear();
18647            return;
18648        }
18649
18650        let debounce_ms = ProjectSettings::get_global(cx)
18651            .diagnostics
18652            .inline
18653            .update_debounce_ms;
18654        let debounce = if debounce && debounce_ms > 0 {
18655            Some(Duration::from_millis(debounce_ms))
18656        } else {
18657            None
18658        };
18659        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18660            if let Some(debounce) = debounce {
18661                cx.background_executor().timer(debounce).await;
18662            }
18663            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18664                editor
18665                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18666                    .ok()
18667            }) else {
18668                return;
18669            };
18670
18671            let new_inline_diagnostics = cx
18672                .background_spawn(async move {
18673                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18674                    for diagnostic_entry in
18675                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18676                    {
18677                        let message = diagnostic_entry
18678                            .diagnostic
18679                            .message
18680                            .split_once('\n')
18681                            .map(|(line, _)| line)
18682                            .map(SharedString::new)
18683                            .unwrap_or_else(|| {
18684                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18685                            });
18686                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18687                        let (Ok(i) | Err(i)) = inline_diagnostics
18688                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18689                        inline_diagnostics.insert(
18690                            i,
18691                            (
18692                                start_anchor,
18693                                InlineDiagnostic {
18694                                    message,
18695                                    group_id: diagnostic_entry.diagnostic.group_id,
18696                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18697                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18698                                    severity: diagnostic_entry.diagnostic.severity,
18699                                },
18700                            ),
18701                        );
18702                    }
18703                    inline_diagnostics
18704                })
18705                .await;
18706
18707            editor
18708                .update(cx, |editor, cx| {
18709                    editor.inline_diagnostics = new_inline_diagnostics;
18710                    cx.notify();
18711                })
18712                .ok();
18713        });
18714    }
18715
18716    fn pull_diagnostics(
18717        &mut self,
18718        buffer_id: Option<BufferId>,
18719        window: &Window,
18720        cx: &mut Context<Self>,
18721    ) -> Option<()> {
18722        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18723            return None;
18724        }
18725        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18726            .diagnostics
18727            .lsp_pull_diagnostics;
18728        if !pull_diagnostics_settings.enabled {
18729            return None;
18730        }
18731        let project = self.project()?.downgrade();
18732
18733        let mut edited_buffer_ids = HashSet::default();
18734        let mut edited_worktree_ids = HashSet::default();
18735        let edited_buffers = match buffer_id {
18736            Some(buffer_id) => {
18737                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18738                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18739                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18740                edited_worktree_ids.insert(worktree_id);
18741                vec![buffer]
18742            }
18743            None => self
18744                .buffer()
18745                .read(cx)
18746                .all_buffers()
18747                .into_iter()
18748                .filter(|buffer| {
18749                    let buffer = buffer.read(cx);
18750                    match buffer.file().map(|f| f.worktree_id(cx)) {
18751                        Some(worktree_id) => {
18752                            edited_buffer_ids.insert(buffer.remote_id());
18753                            edited_worktree_ids.insert(worktree_id);
18754                            true
18755                        }
18756                        None => false,
18757                    }
18758                })
18759                .collect::<Vec<_>>(),
18760        };
18761
18762        if edited_buffers.is_empty() {
18763            self.pull_diagnostics_task = Task::ready(());
18764            self.pull_diagnostics_background_task = Task::ready(());
18765            return None;
18766        }
18767
18768        let mut already_used_buffers = HashSet::default();
18769        let related_open_buffers = self
18770            .workspace
18771            .as_ref()
18772            .and_then(|(workspace, _)| workspace.upgrade())
18773            .into_iter()
18774            .flat_map(|workspace| workspace.read(cx).panes())
18775            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18776            .filter(|editor| editor != &cx.entity())
18777            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18778            .filter(|buffer| {
18779                let buffer = buffer.read(cx);
18780                let buffer_id = buffer.remote_id();
18781                if already_used_buffers.insert(buffer_id) {
18782                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18783                        return !edited_buffer_ids.contains(&buffer_id)
18784                            && !edited_worktree_ids.contains(&worktree_id);
18785                    }
18786                }
18787                false
18788            })
18789            .collect::<Vec<_>>();
18790
18791        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18792        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18793            if buffers.is_empty() {
18794                return Task::ready(());
18795            }
18796            let project_weak = project.clone();
18797            cx.spawn_in(window, async move |_, cx| {
18798                cx.background_executor().timer(delay).await;
18799
18800                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18801                    buffers
18802                        .into_iter()
18803                        .filter_map(|buffer| {
18804                            project_weak
18805                                .update(cx, |project, cx| {
18806                                    project.lsp_store().update(cx, |lsp_store, cx| {
18807                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18808                                    })
18809                                })
18810                                .ok()
18811                        })
18812                        .collect::<FuturesUnordered<_>>()
18813                }) else {
18814                    return;
18815                };
18816
18817                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18818                    if let Err(e) = pull_task {
18819                        log::error!("Failed to update project diagnostics: {e:#}");
18820                    }
18821                }
18822            })
18823        };
18824
18825        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18826        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18827
18828        Some(())
18829    }
18830
18831    pub fn set_selections_from_remote(
18832        &mut self,
18833        selections: Vec<Selection<Anchor>>,
18834        pending_selection: Option<Selection<Anchor>>,
18835        window: &mut Window,
18836        cx: &mut Context<Self>,
18837    ) {
18838        let old_cursor_position = self.selections.newest_anchor().head();
18839        self.selections
18840            .change_with(&self.display_snapshot(cx), |s| {
18841                s.select_anchors(selections);
18842                if let Some(pending_selection) = pending_selection {
18843                    s.set_pending(pending_selection, SelectMode::Character);
18844                } else {
18845                    s.clear_pending();
18846                }
18847            });
18848        self.selections_did_change(
18849            false,
18850            &old_cursor_position,
18851            SelectionEffects::default(),
18852            window,
18853            cx,
18854        );
18855    }
18856
18857    pub fn transact(
18858        &mut self,
18859        window: &mut Window,
18860        cx: &mut Context<Self>,
18861        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18862    ) -> Option<TransactionId> {
18863        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18864            this.start_transaction_at(Instant::now(), window, cx);
18865            update(this, window, cx);
18866            this.end_transaction_at(Instant::now(), cx)
18867        })
18868    }
18869
18870    pub fn start_transaction_at(
18871        &mut self,
18872        now: Instant,
18873        window: &mut Window,
18874        cx: &mut Context<Self>,
18875    ) -> Option<TransactionId> {
18876        self.end_selection(window, cx);
18877        if let Some(tx_id) = self
18878            .buffer
18879            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18880        {
18881            self.selection_history
18882                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18883            cx.emit(EditorEvent::TransactionBegun {
18884                transaction_id: tx_id,
18885            });
18886            Some(tx_id)
18887        } else {
18888            None
18889        }
18890    }
18891
18892    pub fn end_transaction_at(
18893        &mut self,
18894        now: Instant,
18895        cx: &mut Context<Self>,
18896    ) -> Option<TransactionId> {
18897        if let Some(transaction_id) = self
18898            .buffer
18899            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18900        {
18901            if let Some((_, end_selections)) =
18902                self.selection_history.transaction_mut(transaction_id)
18903            {
18904                *end_selections = Some(self.selections.disjoint_anchors_arc());
18905            } else {
18906                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18907            }
18908
18909            cx.emit(EditorEvent::Edited { transaction_id });
18910            Some(transaction_id)
18911        } else {
18912            None
18913        }
18914    }
18915
18916    pub fn modify_transaction_selection_history(
18917        &mut self,
18918        transaction_id: TransactionId,
18919        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18920    ) -> bool {
18921        self.selection_history
18922            .transaction_mut(transaction_id)
18923            .map(modify)
18924            .is_some()
18925    }
18926
18927    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18928        if self.selection_mark_mode {
18929            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18930                s.move_with(|_, sel| {
18931                    sel.collapse_to(sel.head(), SelectionGoal::None);
18932                });
18933            })
18934        }
18935        self.selection_mark_mode = true;
18936        cx.notify();
18937    }
18938
18939    pub fn swap_selection_ends(
18940        &mut self,
18941        _: &actions::SwapSelectionEnds,
18942        window: &mut Window,
18943        cx: &mut Context<Self>,
18944    ) {
18945        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18946            s.move_with(|_, sel| {
18947                if sel.start != sel.end {
18948                    sel.reversed = !sel.reversed
18949                }
18950            });
18951        });
18952        self.request_autoscroll(Autoscroll::newest(), cx);
18953        cx.notify();
18954    }
18955
18956    pub fn toggle_focus(
18957        workspace: &mut Workspace,
18958        _: &actions::ToggleFocus,
18959        window: &mut Window,
18960        cx: &mut Context<Workspace>,
18961    ) {
18962        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18963            return;
18964        };
18965        workspace.activate_item(&item, true, true, window, cx);
18966    }
18967
18968    pub fn toggle_fold(
18969        &mut self,
18970        _: &actions::ToggleFold,
18971        window: &mut Window,
18972        cx: &mut Context<Self>,
18973    ) {
18974        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18975            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18976            let selection = self.selections.newest::<Point>(&display_map);
18977
18978            let range = if selection.is_empty() {
18979                let point = selection.head().to_display_point(&display_map);
18980                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18981                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18982                    .to_point(&display_map);
18983                start..end
18984            } else {
18985                selection.range()
18986            };
18987            if display_map.folds_in_range(range).next().is_some() {
18988                self.unfold_lines(&Default::default(), window, cx)
18989            } else {
18990                self.fold(&Default::default(), window, cx)
18991            }
18992        } else {
18993            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18994            let buffer_ids: HashSet<_> = self
18995                .selections
18996                .disjoint_anchor_ranges()
18997                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18998                .collect();
18999
19000            let should_unfold = buffer_ids
19001                .iter()
19002                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19003
19004            for buffer_id in buffer_ids {
19005                if should_unfold {
19006                    self.unfold_buffer(buffer_id, cx);
19007                } else {
19008                    self.fold_buffer(buffer_id, cx);
19009                }
19010            }
19011        }
19012    }
19013
19014    pub fn toggle_fold_recursive(
19015        &mut self,
19016        _: &actions::ToggleFoldRecursive,
19017        window: &mut Window,
19018        cx: &mut Context<Self>,
19019    ) {
19020        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19021
19022        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19023        let range = if selection.is_empty() {
19024            let point = selection.head().to_display_point(&display_map);
19025            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19026            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19027                .to_point(&display_map);
19028            start..end
19029        } else {
19030            selection.range()
19031        };
19032        if display_map.folds_in_range(range).next().is_some() {
19033            self.unfold_recursive(&Default::default(), window, cx)
19034        } else {
19035            self.fold_recursive(&Default::default(), window, cx)
19036        }
19037    }
19038
19039    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19040        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19041            let mut to_fold = Vec::new();
19042            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19043            let selections = self.selections.all_adjusted(&display_map);
19044
19045            for selection in selections {
19046                let range = selection.range().sorted();
19047                let buffer_start_row = range.start.row;
19048
19049                if range.start.row != range.end.row {
19050                    let mut found = false;
19051                    let mut row = range.start.row;
19052                    while row <= range.end.row {
19053                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19054                        {
19055                            found = true;
19056                            row = crease.range().end.row + 1;
19057                            to_fold.push(crease);
19058                        } else {
19059                            row += 1
19060                        }
19061                    }
19062                    if found {
19063                        continue;
19064                    }
19065                }
19066
19067                for row in (0..=range.start.row).rev() {
19068                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19069                        && crease.range().end.row >= buffer_start_row
19070                    {
19071                        to_fold.push(crease);
19072                        if row <= range.start.row {
19073                            break;
19074                        }
19075                    }
19076                }
19077            }
19078
19079            self.fold_creases(to_fold, true, window, cx);
19080        } else {
19081            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19082            let buffer_ids = self
19083                .selections
19084                .disjoint_anchor_ranges()
19085                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19086                .collect::<HashSet<_>>();
19087            for buffer_id in buffer_ids {
19088                self.fold_buffer(buffer_id, cx);
19089            }
19090        }
19091    }
19092
19093    pub fn toggle_fold_all(
19094        &mut self,
19095        _: &actions::ToggleFoldAll,
19096        window: &mut Window,
19097        cx: &mut Context<Self>,
19098    ) {
19099        if self.buffer.read(cx).is_singleton() {
19100            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19101            let has_folds = display_map
19102                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19103                .next()
19104                .is_some();
19105
19106            if has_folds {
19107                self.unfold_all(&actions::UnfoldAll, window, cx);
19108            } else {
19109                self.fold_all(&actions::FoldAll, window, cx);
19110            }
19111        } else {
19112            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19113            let should_unfold = buffer_ids
19114                .iter()
19115                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19116
19117            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19118                editor
19119                    .update_in(cx, |editor, _, cx| {
19120                        for buffer_id in buffer_ids {
19121                            if should_unfold {
19122                                editor.unfold_buffer(buffer_id, cx);
19123                            } else {
19124                                editor.fold_buffer(buffer_id, cx);
19125                            }
19126                        }
19127                    })
19128                    .ok();
19129            });
19130        }
19131    }
19132
19133    fn fold_at_level(
19134        &mut self,
19135        fold_at: &FoldAtLevel,
19136        window: &mut Window,
19137        cx: &mut Context<Self>,
19138    ) {
19139        if !self.buffer.read(cx).is_singleton() {
19140            return;
19141        }
19142
19143        let fold_at_level = fold_at.0;
19144        let snapshot = self.buffer.read(cx).snapshot(cx);
19145        let mut to_fold = Vec::new();
19146        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19147
19148        let row_ranges_to_keep: Vec<Range<u32>> = self
19149            .selections
19150            .all::<Point>(&self.display_snapshot(cx))
19151            .into_iter()
19152            .map(|sel| sel.start.row..sel.end.row)
19153            .collect();
19154
19155        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19156            while start_row < end_row {
19157                match self
19158                    .snapshot(window, cx)
19159                    .crease_for_buffer_row(MultiBufferRow(start_row))
19160                {
19161                    Some(crease) => {
19162                        let nested_start_row = crease.range().start.row + 1;
19163                        let nested_end_row = crease.range().end.row;
19164
19165                        if current_level < fold_at_level {
19166                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19167                        } else if current_level == fold_at_level {
19168                            // Fold iff there is no selection completely contained within the fold region
19169                            if !row_ranges_to_keep.iter().any(|selection| {
19170                                selection.end >= nested_start_row
19171                                    && selection.start <= nested_end_row
19172                            }) {
19173                                to_fold.push(crease);
19174                            }
19175                        }
19176
19177                        start_row = nested_end_row + 1;
19178                    }
19179                    None => start_row += 1,
19180                }
19181            }
19182        }
19183
19184        self.fold_creases(to_fold, true, window, cx);
19185    }
19186
19187    pub fn fold_at_level_1(
19188        &mut self,
19189        _: &actions::FoldAtLevel1,
19190        window: &mut Window,
19191        cx: &mut Context<Self>,
19192    ) {
19193        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19194    }
19195
19196    pub fn fold_at_level_2(
19197        &mut self,
19198        _: &actions::FoldAtLevel2,
19199        window: &mut Window,
19200        cx: &mut Context<Self>,
19201    ) {
19202        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19203    }
19204
19205    pub fn fold_at_level_3(
19206        &mut self,
19207        _: &actions::FoldAtLevel3,
19208        window: &mut Window,
19209        cx: &mut Context<Self>,
19210    ) {
19211        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19212    }
19213
19214    pub fn fold_at_level_4(
19215        &mut self,
19216        _: &actions::FoldAtLevel4,
19217        window: &mut Window,
19218        cx: &mut Context<Self>,
19219    ) {
19220        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19221    }
19222
19223    pub fn fold_at_level_5(
19224        &mut self,
19225        _: &actions::FoldAtLevel5,
19226        window: &mut Window,
19227        cx: &mut Context<Self>,
19228    ) {
19229        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19230    }
19231
19232    pub fn fold_at_level_6(
19233        &mut self,
19234        _: &actions::FoldAtLevel6,
19235        window: &mut Window,
19236        cx: &mut Context<Self>,
19237    ) {
19238        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19239    }
19240
19241    pub fn fold_at_level_7(
19242        &mut self,
19243        _: &actions::FoldAtLevel7,
19244        window: &mut Window,
19245        cx: &mut Context<Self>,
19246    ) {
19247        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19248    }
19249
19250    pub fn fold_at_level_8(
19251        &mut self,
19252        _: &actions::FoldAtLevel8,
19253        window: &mut Window,
19254        cx: &mut Context<Self>,
19255    ) {
19256        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19257    }
19258
19259    pub fn fold_at_level_9(
19260        &mut self,
19261        _: &actions::FoldAtLevel9,
19262        window: &mut Window,
19263        cx: &mut Context<Self>,
19264    ) {
19265        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19266    }
19267
19268    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19269        if self.buffer.read(cx).is_singleton() {
19270            let mut fold_ranges = Vec::new();
19271            let snapshot = self.buffer.read(cx).snapshot(cx);
19272
19273            for row in 0..snapshot.max_row().0 {
19274                if let Some(foldable_range) = self
19275                    .snapshot(window, cx)
19276                    .crease_for_buffer_row(MultiBufferRow(row))
19277                {
19278                    fold_ranges.push(foldable_range);
19279                }
19280            }
19281
19282            self.fold_creases(fold_ranges, true, window, cx);
19283        } else {
19284            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19285                editor
19286                    .update_in(cx, |editor, _, cx| {
19287                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19288                            editor.fold_buffer(buffer_id, cx);
19289                        }
19290                    })
19291                    .ok();
19292            });
19293        }
19294    }
19295
19296    pub fn fold_function_bodies(
19297        &mut self,
19298        _: &actions::FoldFunctionBodies,
19299        window: &mut Window,
19300        cx: &mut Context<Self>,
19301    ) {
19302        let snapshot = self.buffer.read(cx).snapshot(cx);
19303
19304        let ranges = snapshot
19305            .text_object_ranges(
19306                MultiBufferOffset(0)..snapshot.len(),
19307                TreeSitterOptions::default(),
19308            )
19309            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19310            .collect::<Vec<_>>();
19311
19312        let creases = ranges
19313            .into_iter()
19314            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19315            .collect();
19316
19317        self.fold_creases(creases, true, window, cx);
19318    }
19319
19320    pub fn fold_recursive(
19321        &mut self,
19322        _: &actions::FoldRecursive,
19323        window: &mut Window,
19324        cx: &mut Context<Self>,
19325    ) {
19326        let mut to_fold = Vec::new();
19327        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19328        let selections = self.selections.all_adjusted(&display_map);
19329
19330        for selection in selections {
19331            let range = selection.range().sorted();
19332            let buffer_start_row = range.start.row;
19333
19334            if range.start.row != range.end.row {
19335                let mut found = false;
19336                for row in range.start.row..=range.end.row {
19337                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19338                        found = true;
19339                        to_fold.push(crease);
19340                    }
19341                }
19342                if found {
19343                    continue;
19344                }
19345            }
19346
19347            for row in (0..=range.start.row).rev() {
19348                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19349                    if crease.range().end.row >= buffer_start_row {
19350                        to_fold.push(crease);
19351                    } else {
19352                        break;
19353                    }
19354                }
19355            }
19356        }
19357
19358        self.fold_creases(to_fold, true, window, cx);
19359    }
19360
19361    pub fn fold_at(
19362        &mut self,
19363        buffer_row: MultiBufferRow,
19364        window: &mut Window,
19365        cx: &mut Context<Self>,
19366    ) {
19367        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19368
19369        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19370            let autoscroll = self
19371                .selections
19372                .all::<Point>(&display_map)
19373                .iter()
19374                .any(|selection| crease.range().overlaps(&selection.range()));
19375
19376            self.fold_creases(vec![crease], autoscroll, window, cx);
19377        }
19378    }
19379
19380    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19381        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19382            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19383            let buffer = display_map.buffer_snapshot();
19384            let selections = self.selections.all::<Point>(&display_map);
19385            let ranges = selections
19386                .iter()
19387                .map(|s| {
19388                    let range = s.display_range(&display_map).sorted();
19389                    let mut start = range.start.to_point(&display_map);
19390                    let mut end = range.end.to_point(&display_map);
19391                    start.column = 0;
19392                    end.column = buffer.line_len(MultiBufferRow(end.row));
19393                    start..end
19394                })
19395                .collect::<Vec<_>>();
19396
19397            self.unfold_ranges(&ranges, true, true, cx);
19398        } else {
19399            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19400            let buffer_ids = self
19401                .selections
19402                .disjoint_anchor_ranges()
19403                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19404                .collect::<HashSet<_>>();
19405            for buffer_id in buffer_ids {
19406                self.unfold_buffer(buffer_id, cx);
19407            }
19408        }
19409    }
19410
19411    pub fn unfold_recursive(
19412        &mut self,
19413        _: &UnfoldRecursive,
19414        _window: &mut Window,
19415        cx: &mut Context<Self>,
19416    ) {
19417        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19418        let selections = self.selections.all::<Point>(&display_map);
19419        let ranges = selections
19420            .iter()
19421            .map(|s| {
19422                let mut range = s.display_range(&display_map).sorted();
19423                *range.start.column_mut() = 0;
19424                *range.end.column_mut() = display_map.line_len(range.end.row());
19425                let start = range.start.to_point(&display_map);
19426                let end = range.end.to_point(&display_map);
19427                start..end
19428            })
19429            .collect::<Vec<_>>();
19430
19431        self.unfold_ranges(&ranges, true, true, cx);
19432    }
19433
19434    pub fn unfold_at(
19435        &mut self,
19436        buffer_row: MultiBufferRow,
19437        _window: &mut Window,
19438        cx: &mut Context<Self>,
19439    ) {
19440        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19441
19442        let intersection_range = Point::new(buffer_row.0, 0)
19443            ..Point::new(
19444                buffer_row.0,
19445                display_map.buffer_snapshot().line_len(buffer_row),
19446            );
19447
19448        let autoscroll = self
19449            .selections
19450            .all::<Point>(&display_map)
19451            .iter()
19452            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19453
19454        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19455    }
19456
19457    pub fn unfold_all(
19458        &mut self,
19459        _: &actions::UnfoldAll,
19460        _window: &mut Window,
19461        cx: &mut Context<Self>,
19462    ) {
19463        if self.buffer.read(cx).is_singleton() {
19464            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19465            self.unfold_ranges(
19466                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19467                true,
19468                true,
19469                cx,
19470            );
19471        } else {
19472            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19473                editor
19474                    .update(cx, |editor, cx| {
19475                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19476                            editor.unfold_buffer(buffer_id, cx);
19477                        }
19478                    })
19479                    .ok();
19480            });
19481        }
19482    }
19483
19484    pub fn fold_selected_ranges(
19485        &mut self,
19486        _: &FoldSelectedRanges,
19487        window: &mut Window,
19488        cx: &mut Context<Self>,
19489    ) {
19490        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19491        let selections = self.selections.all_adjusted(&display_map);
19492        let ranges = selections
19493            .into_iter()
19494            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19495            .collect::<Vec<_>>();
19496        self.fold_creases(ranges, true, window, cx);
19497    }
19498
19499    pub fn fold_ranges<T: ToOffset + Clone>(
19500        &mut self,
19501        ranges: Vec<Range<T>>,
19502        auto_scroll: bool,
19503        window: &mut Window,
19504        cx: &mut Context<Self>,
19505    ) {
19506        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19507        let ranges = ranges
19508            .into_iter()
19509            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19510            .collect::<Vec<_>>();
19511        self.fold_creases(ranges, auto_scroll, window, cx);
19512    }
19513
19514    pub fn fold_creases<T: ToOffset + Clone>(
19515        &mut self,
19516        creases: Vec<Crease<T>>,
19517        auto_scroll: bool,
19518        _window: &mut Window,
19519        cx: &mut Context<Self>,
19520    ) {
19521        if creases.is_empty() {
19522            return;
19523        }
19524
19525        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19526
19527        if auto_scroll {
19528            self.request_autoscroll(Autoscroll::fit(), cx);
19529        }
19530
19531        cx.notify();
19532
19533        self.scrollbar_marker_state.dirty = true;
19534        self.folds_did_change(cx);
19535    }
19536
19537    /// Removes any folds whose ranges intersect any of the given ranges.
19538    pub fn unfold_ranges<T: ToOffset + Clone>(
19539        &mut self,
19540        ranges: &[Range<T>],
19541        inclusive: bool,
19542        auto_scroll: bool,
19543        cx: &mut Context<Self>,
19544    ) {
19545        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19546            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19547        });
19548        self.folds_did_change(cx);
19549    }
19550
19551    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19552        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19553            return;
19554        }
19555
19556        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19557        self.display_map.update(cx, |display_map, cx| {
19558            display_map.fold_buffers([buffer_id], cx)
19559        });
19560
19561        let snapshot = self.display_snapshot(cx);
19562        self.selections.change_with(&snapshot, |selections| {
19563            selections.remove_selections_from_buffer(buffer_id);
19564        });
19565
19566        cx.emit(EditorEvent::BufferFoldToggled {
19567            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19568            folded: true,
19569        });
19570        cx.notify();
19571    }
19572
19573    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19574        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19575            return;
19576        }
19577        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19578        self.display_map.update(cx, |display_map, cx| {
19579            display_map.unfold_buffers([buffer_id], cx);
19580        });
19581        cx.emit(EditorEvent::BufferFoldToggled {
19582            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19583            folded: false,
19584        });
19585        cx.notify();
19586    }
19587
19588    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19589        self.display_map.read(cx).is_buffer_folded(buffer)
19590    }
19591
19592    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19593        self.display_map.read(cx).folded_buffers()
19594    }
19595
19596    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19597        self.display_map.update(cx, |display_map, cx| {
19598            display_map.disable_header_for_buffer(buffer_id, cx);
19599        });
19600        cx.notify();
19601    }
19602
19603    /// Removes any folds with the given ranges.
19604    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19605        &mut self,
19606        ranges: &[Range<T>],
19607        type_id: TypeId,
19608        auto_scroll: bool,
19609        cx: &mut Context<Self>,
19610    ) {
19611        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19612            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19613        });
19614        self.folds_did_change(cx);
19615    }
19616
19617    fn remove_folds_with<T: ToOffset + Clone>(
19618        &mut self,
19619        ranges: &[Range<T>],
19620        auto_scroll: bool,
19621        cx: &mut Context<Self>,
19622        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19623    ) {
19624        if ranges.is_empty() {
19625            return;
19626        }
19627
19628        let mut buffers_affected = HashSet::default();
19629        let multi_buffer = self.buffer().read(cx);
19630        for range in ranges {
19631            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19632                buffers_affected.insert(buffer.read(cx).remote_id());
19633            };
19634        }
19635
19636        self.display_map.update(cx, update);
19637
19638        if auto_scroll {
19639            self.request_autoscroll(Autoscroll::fit(), cx);
19640        }
19641
19642        cx.notify();
19643        self.scrollbar_marker_state.dirty = true;
19644        self.active_indent_guides_state.dirty = true;
19645    }
19646
19647    pub fn update_renderer_widths(
19648        &mut self,
19649        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19650        cx: &mut Context<Self>,
19651    ) -> bool {
19652        self.display_map
19653            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19654    }
19655
19656    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19657        self.display_map.read(cx).fold_placeholder.clone()
19658    }
19659
19660    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19661        self.use_base_text_line_numbers = show;
19662    }
19663
19664    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19665        self.buffer.update(cx, |buffer, cx| {
19666            buffer.set_all_diff_hunks_expanded(cx);
19667        });
19668    }
19669
19670    pub fn expand_all_diff_hunks(
19671        &mut self,
19672        _: &ExpandAllDiffHunks,
19673        _window: &mut Window,
19674        cx: &mut Context<Self>,
19675    ) {
19676        self.buffer.update(cx, |buffer, cx| {
19677            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19678        });
19679    }
19680
19681    pub fn collapse_all_diff_hunks(
19682        &mut self,
19683        _: &CollapseAllDiffHunks,
19684        _window: &mut Window,
19685        cx: &mut Context<Self>,
19686    ) {
19687        self.buffer.update(cx, |buffer, cx| {
19688            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19689        });
19690    }
19691
19692    pub fn toggle_selected_diff_hunks(
19693        &mut self,
19694        _: &ToggleSelectedDiffHunks,
19695        _window: &mut Window,
19696        cx: &mut Context<Self>,
19697    ) {
19698        let ranges: Vec<_> = self
19699            .selections
19700            .disjoint_anchors()
19701            .iter()
19702            .map(|s| s.range())
19703            .collect();
19704        self.toggle_diff_hunks_in_ranges(ranges, cx);
19705    }
19706
19707    pub fn diff_hunks_in_ranges<'a>(
19708        &'a self,
19709        ranges: &'a [Range<Anchor>],
19710        buffer: &'a MultiBufferSnapshot,
19711    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19712        ranges.iter().flat_map(move |range| {
19713            let end_excerpt_id = range.end.excerpt_id;
19714            let range = range.to_point(buffer);
19715            let mut peek_end = range.end;
19716            if range.end.row < buffer.max_row().0 {
19717                peek_end = Point::new(range.end.row + 1, 0);
19718            }
19719            buffer
19720                .diff_hunks_in_range(range.start..peek_end)
19721                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19722        })
19723    }
19724
19725    pub fn has_stageable_diff_hunks_in_ranges(
19726        &self,
19727        ranges: &[Range<Anchor>],
19728        snapshot: &MultiBufferSnapshot,
19729    ) -> bool {
19730        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19731        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19732    }
19733
19734    pub fn toggle_staged_selected_diff_hunks(
19735        &mut self,
19736        _: &::git::ToggleStaged,
19737        _: &mut Window,
19738        cx: &mut Context<Self>,
19739    ) {
19740        let snapshot = self.buffer.read(cx).snapshot(cx);
19741        let ranges: Vec<_> = self
19742            .selections
19743            .disjoint_anchors()
19744            .iter()
19745            .map(|s| s.range())
19746            .collect();
19747        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19748        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19749    }
19750
19751    pub fn set_render_diff_hunk_controls(
19752        &mut self,
19753        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19754        cx: &mut Context<Self>,
19755    ) {
19756        self.render_diff_hunk_controls = render_diff_hunk_controls;
19757        cx.notify();
19758    }
19759
19760    pub fn stage_and_next(
19761        &mut self,
19762        _: &::git::StageAndNext,
19763        window: &mut Window,
19764        cx: &mut Context<Self>,
19765    ) {
19766        self.do_stage_or_unstage_and_next(true, window, cx);
19767    }
19768
19769    pub fn unstage_and_next(
19770        &mut self,
19771        _: &::git::UnstageAndNext,
19772        window: &mut Window,
19773        cx: &mut Context<Self>,
19774    ) {
19775        self.do_stage_or_unstage_and_next(false, window, cx);
19776    }
19777
19778    pub fn stage_or_unstage_diff_hunks(
19779        &mut self,
19780        stage: bool,
19781        ranges: Vec<Range<Anchor>>,
19782        cx: &mut Context<Self>,
19783    ) {
19784        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19785        cx.spawn(async move |this, cx| {
19786            task.await?;
19787            this.update(cx, |this, cx| {
19788                let snapshot = this.buffer.read(cx).snapshot(cx);
19789                let chunk_by = this
19790                    .diff_hunks_in_ranges(&ranges, &snapshot)
19791                    .chunk_by(|hunk| hunk.buffer_id);
19792                for (buffer_id, hunks) in &chunk_by {
19793                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19794                }
19795            })
19796        })
19797        .detach_and_log_err(cx);
19798    }
19799
19800    fn save_buffers_for_ranges_if_needed(
19801        &mut self,
19802        ranges: &[Range<Anchor>],
19803        cx: &mut Context<Editor>,
19804    ) -> Task<Result<()>> {
19805        let multibuffer = self.buffer.read(cx);
19806        let snapshot = multibuffer.read(cx);
19807        let buffer_ids: HashSet<_> = ranges
19808            .iter()
19809            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19810            .collect();
19811        drop(snapshot);
19812
19813        let mut buffers = HashSet::default();
19814        for buffer_id in buffer_ids {
19815            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19816                let buffer = buffer_entity.read(cx);
19817                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19818                {
19819                    buffers.insert(buffer_entity);
19820                }
19821            }
19822        }
19823
19824        if let Some(project) = &self.project {
19825            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19826        } else {
19827            Task::ready(Ok(()))
19828        }
19829    }
19830
19831    fn do_stage_or_unstage_and_next(
19832        &mut self,
19833        stage: bool,
19834        window: &mut Window,
19835        cx: &mut Context<Self>,
19836    ) {
19837        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19838
19839        if ranges.iter().any(|range| range.start != range.end) {
19840            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19841            return;
19842        }
19843
19844        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19845        let snapshot = self.snapshot(window, cx);
19846        let position = self
19847            .selections
19848            .newest::<Point>(&snapshot.display_snapshot)
19849            .head();
19850        let mut row = snapshot
19851            .buffer_snapshot()
19852            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19853            .find(|hunk| hunk.row_range.start.0 > position.row)
19854            .map(|hunk| hunk.row_range.start);
19855
19856        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19857        // Outside of the project diff editor, wrap around to the beginning.
19858        if !all_diff_hunks_expanded {
19859            row = row.or_else(|| {
19860                snapshot
19861                    .buffer_snapshot()
19862                    .diff_hunks_in_range(Point::zero()..position)
19863                    .find(|hunk| hunk.row_range.end.0 < position.row)
19864                    .map(|hunk| hunk.row_range.start)
19865            });
19866        }
19867
19868        if let Some(row) = row {
19869            let destination = Point::new(row.0, 0);
19870            let autoscroll = Autoscroll::center();
19871
19872            self.unfold_ranges(&[destination..destination], false, false, cx);
19873            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19874                s.select_ranges([destination..destination]);
19875            });
19876        }
19877    }
19878
19879    fn do_stage_or_unstage(
19880        &self,
19881        stage: bool,
19882        buffer_id: BufferId,
19883        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19884        cx: &mut App,
19885    ) -> Option<()> {
19886        let project = self.project()?;
19887        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19888        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19889        let buffer_snapshot = buffer.read(cx).snapshot();
19890        let file_exists = buffer_snapshot
19891            .file()
19892            .is_some_and(|file| file.disk_state().exists());
19893        diff.update(cx, |diff, cx| {
19894            diff.stage_or_unstage_hunks(
19895                stage,
19896                &hunks
19897                    .map(|hunk| buffer_diff::DiffHunk {
19898                        buffer_range: hunk.buffer_range,
19899                        // We don't need to pass in word diffs here because they're only used for rendering and
19900                        // this function changes internal state
19901                        base_word_diffs: Vec::default(),
19902                        buffer_word_diffs: Vec::default(),
19903                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19904                            ..hunk.diff_base_byte_range.end.0,
19905                        secondary_status: hunk.secondary_status,
19906                        range: Point::zero()..Point::zero(), // unused
19907                    })
19908                    .collect::<Vec<_>>(),
19909                &buffer_snapshot,
19910                file_exists,
19911                cx,
19912            )
19913        });
19914        None
19915    }
19916
19917    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19918        let ranges: Vec<_> = self
19919            .selections
19920            .disjoint_anchors()
19921            .iter()
19922            .map(|s| s.range())
19923            .collect();
19924        self.buffer
19925            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19926    }
19927
19928    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19929        self.buffer.update(cx, |buffer, cx| {
19930            let ranges = vec![Anchor::min()..Anchor::max()];
19931            if !buffer.all_diff_hunks_expanded()
19932                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19933            {
19934                buffer.collapse_diff_hunks(ranges, cx);
19935                true
19936            } else {
19937                false
19938            }
19939        })
19940    }
19941
19942    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19943        if self.buffer.read(cx).all_diff_hunks_expanded() {
19944            return true;
19945        }
19946        let ranges = vec![Anchor::min()..Anchor::max()];
19947        self.buffer
19948            .read(cx)
19949            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19950    }
19951
19952    fn toggle_diff_hunks_in_ranges(
19953        &mut self,
19954        ranges: Vec<Range<Anchor>>,
19955        cx: &mut Context<Editor>,
19956    ) {
19957        self.buffer.update(cx, |buffer, cx| {
19958            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19959            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19960        })
19961    }
19962
19963    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19964        self.buffer.update(cx, |buffer, cx| {
19965            let snapshot = buffer.snapshot(cx);
19966            let excerpt_id = range.end.excerpt_id;
19967            let point_range = range.to_point(&snapshot);
19968            let expand = !buffer.single_hunk_is_expanded(range, cx);
19969            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19970        })
19971    }
19972
19973    pub(crate) fn apply_all_diff_hunks(
19974        &mut self,
19975        _: &ApplyAllDiffHunks,
19976        window: &mut Window,
19977        cx: &mut Context<Self>,
19978    ) {
19979        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19980
19981        let buffers = self.buffer.read(cx).all_buffers();
19982        for branch_buffer in buffers {
19983            branch_buffer.update(cx, |branch_buffer, cx| {
19984                branch_buffer.merge_into_base(Vec::new(), cx);
19985            });
19986        }
19987
19988        if let Some(project) = self.project.clone() {
19989            self.save(
19990                SaveOptions {
19991                    format: true,
19992                    autosave: false,
19993                },
19994                project,
19995                window,
19996                cx,
19997            )
19998            .detach_and_log_err(cx);
19999        }
20000    }
20001
20002    pub(crate) fn apply_selected_diff_hunks(
20003        &mut self,
20004        _: &ApplyDiffHunk,
20005        window: &mut Window,
20006        cx: &mut Context<Self>,
20007    ) {
20008        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20009        let snapshot = self.snapshot(window, cx);
20010        let hunks = snapshot.hunks_for_ranges(
20011            self.selections
20012                .all(&snapshot.display_snapshot)
20013                .into_iter()
20014                .map(|selection| selection.range()),
20015        );
20016        let mut ranges_by_buffer = HashMap::default();
20017        self.transact(window, cx, |editor, _window, cx| {
20018            for hunk in hunks {
20019                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20020                    ranges_by_buffer
20021                        .entry(buffer.clone())
20022                        .or_insert_with(Vec::new)
20023                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20024                }
20025            }
20026
20027            for (buffer, ranges) in ranges_by_buffer {
20028                buffer.update(cx, |buffer, cx| {
20029                    buffer.merge_into_base(ranges, cx);
20030                });
20031            }
20032        });
20033
20034        if let Some(project) = self.project.clone() {
20035            self.save(
20036                SaveOptions {
20037                    format: true,
20038                    autosave: false,
20039                },
20040                project,
20041                window,
20042                cx,
20043            )
20044            .detach_and_log_err(cx);
20045        }
20046    }
20047
20048    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20049        if hovered != self.gutter_hovered {
20050            self.gutter_hovered = hovered;
20051            cx.notify();
20052        }
20053    }
20054
20055    pub fn insert_blocks(
20056        &mut self,
20057        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20058        autoscroll: Option<Autoscroll>,
20059        cx: &mut Context<Self>,
20060    ) -> Vec<CustomBlockId> {
20061        let blocks = self
20062            .display_map
20063            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20064        if let Some(autoscroll) = autoscroll {
20065            self.request_autoscroll(autoscroll, cx);
20066        }
20067        cx.notify();
20068        blocks
20069    }
20070
20071    pub fn resize_blocks(
20072        &mut self,
20073        heights: HashMap<CustomBlockId, u32>,
20074        autoscroll: Option<Autoscroll>,
20075        cx: &mut Context<Self>,
20076    ) {
20077        self.display_map
20078            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20079        if let Some(autoscroll) = autoscroll {
20080            self.request_autoscroll(autoscroll, cx);
20081        }
20082        cx.notify();
20083    }
20084
20085    pub fn replace_blocks(
20086        &mut self,
20087        renderers: HashMap<CustomBlockId, RenderBlock>,
20088        autoscroll: Option<Autoscroll>,
20089        cx: &mut Context<Self>,
20090    ) {
20091        self.display_map
20092            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20093        if let Some(autoscroll) = autoscroll {
20094            self.request_autoscroll(autoscroll, cx);
20095        }
20096        cx.notify();
20097    }
20098
20099    pub fn remove_blocks(
20100        &mut self,
20101        block_ids: HashSet<CustomBlockId>,
20102        autoscroll: Option<Autoscroll>,
20103        cx: &mut Context<Self>,
20104    ) {
20105        self.display_map.update(cx, |display_map, cx| {
20106            display_map.remove_blocks(block_ids, cx)
20107        });
20108        if let Some(autoscroll) = autoscroll {
20109            self.request_autoscroll(autoscroll, cx);
20110        }
20111        cx.notify();
20112    }
20113
20114    pub fn row_for_block(
20115        &self,
20116        block_id: CustomBlockId,
20117        cx: &mut Context<Self>,
20118    ) -> Option<DisplayRow> {
20119        self.display_map
20120            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20121    }
20122
20123    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20124        self.focused_block = Some(focused_block);
20125    }
20126
20127    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20128        self.focused_block.take()
20129    }
20130
20131    pub fn insert_creases(
20132        &mut self,
20133        creases: impl IntoIterator<Item = Crease<Anchor>>,
20134        cx: &mut Context<Self>,
20135    ) -> Vec<CreaseId> {
20136        self.display_map
20137            .update(cx, |map, cx| map.insert_creases(creases, cx))
20138    }
20139
20140    pub fn remove_creases(
20141        &mut self,
20142        ids: impl IntoIterator<Item = CreaseId>,
20143        cx: &mut Context<Self>,
20144    ) -> Vec<(CreaseId, Range<Anchor>)> {
20145        self.display_map
20146            .update(cx, |map, cx| map.remove_creases(ids, cx))
20147    }
20148
20149    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20150        self.display_map
20151            .update(cx, |map, cx| map.snapshot(cx))
20152            .longest_row()
20153    }
20154
20155    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20156        self.display_map
20157            .update(cx, |map, cx| map.snapshot(cx))
20158            .max_point()
20159    }
20160
20161    pub fn text(&self, cx: &App) -> String {
20162        self.buffer.read(cx).read(cx).text()
20163    }
20164
20165    pub fn is_empty(&self, cx: &App) -> bool {
20166        self.buffer.read(cx).read(cx).is_empty()
20167    }
20168
20169    pub fn text_option(&self, cx: &App) -> Option<String> {
20170        let text = self.text(cx);
20171        let text = text.trim();
20172
20173        if text.is_empty() {
20174            return None;
20175        }
20176
20177        Some(text.to_string())
20178    }
20179
20180    pub fn set_text(
20181        &mut self,
20182        text: impl Into<Arc<str>>,
20183        window: &mut Window,
20184        cx: &mut Context<Self>,
20185    ) {
20186        self.transact(window, cx, |this, _, cx| {
20187            this.buffer
20188                .read(cx)
20189                .as_singleton()
20190                .expect("you can only call set_text on editors for singleton buffers")
20191                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20192        });
20193    }
20194
20195    pub fn display_text(&self, cx: &mut App) -> String {
20196        self.display_map
20197            .update(cx, |map, cx| map.snapshot(cx))
20198            .text()
20199    }
20200
20201    fn create_minimap(
20202        &self,
20203        minimap_settings: MinimapSettings,
20204        window: &mut Window,
20205        cx: &mut Context<Self>,
20206    ) -> Option<Entity<Self>> {
20207        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20208            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20209    }
20210
20211    fn initialize_new_minimap(
20212        &self,
20213        minimap_settings: MinimapSettings,
20214        window: &mut Window,
20215        cx: &mut Context<Self>,
20216    ) -> Entity<Self> {
20217        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20218
20219        let mut minimap = Editor::new_internal(
20220            EditorMode::Minimap {
20221                parent: cx.weak_entity(),
20222            },
20223            self.buffer.clone(),
20224            None,
20225            Some(self.display_map.clone()),
20226            window,
20227            cx,
20228        );
20229        minimap.scroll_manager.clone_state(&self.scroll_manager);
20230        minimap.set_text_style_refinement(TextStyleRefinement {
20231            font_size: Some(MINIMAP_FONT_SIZE),
20232            font_weight: Some(MINIMAP_FONT_WEIGHT),
20233            ..Default::default()
20234        });
20235        minimap.update_minimap_configuration(minimap_settings, cx);
20236        cx.new(|_| minimap)
20237    }
20238
20239    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20240        let current_line_highlight = minimap_settings
20241            .current_line_highlight
20242            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20243        self.set_current_line_highlight(Some(current_line_highlight));
20244    }
20245
20246    pub fn minimap(&self) -> Option<&Entity<Self>> {
20247        self.minimap
20248            .as_ref()
20249            .filter(|_| self.minimap_visibility.visible())
20250    }
20251
20252    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20253        let mut wrap_guides = smallvec![];
20254
20255        if self.show_wrap_guides == Some(false) {
20256            return wrap_guides;
20257        }
20258
20259        let settings = self.buffer.read(cx).language_settings(cx);
20260        if settings.show_wrap_guides {
20261            match self.soft_wrap_mode(cx) {
20262                SoftWrap::Column(soft_wrap) => {
20263                    wrap_guides.push((soft_wrap as usize, true));
20264                }
20265                SoftWrap::Bounded(soft_wrap) => {
20266                    wrap_guides.push((soft_wrap as usize, true));
20267                }
20268                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20269            }
20270            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20271        }
20272
20273        wrap_guides
20274    }
20275
20276    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20277        let settings = self.buffer.read(cx).language_settings(cx);
20278        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20279        match mode {
20280            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20281                SoftWrap::None
20282            }
20283            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20284            language_settings::SoftWrap::PreferredLineLength => {
20285                SoftWrap::Column(settings.preferred_line_length)
20286            }
20287            language_settings::SoftWrap::Bounded => {
20288                SoftWrap::Bounded(settings.preferred_line_length)
20289            }
20290        }
20291    }
20292
20293    pub fn set_soft_wrap_mode(
20294        &mut self,
20295        mode: language_settings::SoftWrap,
20296
20297        cx: &mut Context<Self>,
20298    ) {
20299        self.soft_wrap_mode_override = Some(mode);
20300        cx.notify();
20301    }
20302
20303    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20304        self.hard_wrap = hard_wrap;
20305        cx.notify();
20306    }
20307
20308    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20309        self.text_style_refinement = Some(style);
20310    }
20311
20312    /// called by the Element so we know what style we were most recently rendered with.
20313    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20314        // We intentionally do not inform the display map about the minimap style
20315        // so that wrapping is not recalculated and stays consistent for the editor
20316        // and its linked minimap.
20317        if !self.mode.is_minimap() {
20318            let font = style.text.font();
20319            let font_size = style.text.font_size.to_pixels(window.rem_size());
20320            let display_map = self
20321                .placeholder_display_map
20322                .as_ref()
20323                .filter(|_| self.is_empty(cx))
20324                .unwrap_or(&self.display_map);
20325
20326            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20327        }
20328        self.style = Some(style);
20329    }
20330
20331    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20332        if self.style.is_none() {
20333            self.style = Some(self.create_style(cx));
20334        }
20335        self.style.as_ref().unwrap()
20336    }
20337
20338    // Called by the element. This method is not designed to be called outside of the editor
20339    // element's layout code because it does not notify when rewrapping is computed synchronously.
20340    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20341        if self.is_empty(cx) {
20342            self.placeholder_display_map
20343                .as_ref()
20344                .map_or(false, |display_map| {
20345                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20346                })
20347        } else {
20348            self.display_map
20349                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20350        }
20351    }
20352
20353    pub fn set_soft_wrap(&mut self) {
20354        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20355    }
20356
20357    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20358        if self.soft_wrap_mode_override.is_some() {
20359            self.soft_wrap_mode_override.take();
20360        } else {
20361            let soft_wrap = match self.soft_wrap_mode(cx) {
20362                SoftWrap::GitDiff => return,
20363                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20364                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20365                    language_settings::SoftWrap::None
20366                }
20367            };
20368            self.soft_wrap_mode_override = Some(soft_wrap);
20369        }
20370        cx.notify();
20371    }
20372
20373    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20374        let Some(workspace) = self.workspace() else {
20375            return;
20376        };
20377        let fs = workspace.read(cx).app_state().fs.clone();
20378        let current_show = TabBarSettings::get_global(cx).show;
20379        update_settings_file(fs, cx, move |setting, _| {
20380            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20381        });
20382    }
20383
20384    pub fn toggle_indent_guides(
20385        &mut self,
20386        _: &ToggleIndentGuides,
20387        _: &mut Window,
20388        cx: &mut Context<Self>,
20389    ) {
20390        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20391            self.buffer
20392                .read(cx)
20393                .language_settings(cx)
20394                .indent_guides
20395                .enabled
20396        });
20397        self.show_indent_guides = Some(!currently_enabled);
20398        cx.notify();
20399    }
20400
20401    fn should_show_indent_guides(&self) -> Option<bool> {
20402        self.show_indent_guides
20403    }
20404
20405    pub fn disable_indent_guides_for_buffer(
20406        &mut self,
20407        buffer_id: BufferId,
20408        cx: &mut Context<Self>,
20409    ) {
20410        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20411        cx.notify();
20412    }
20413
20414    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20415        self.buffers_with_disabled_indent_guides
20416            .contains(&buffer_id)
20417    }
20418
20419    pub fn toggle_line_numbers(
20420        &mut self,
20421        _: &ToggleLineNumbers,
20422        _: &mut Window,
20423        cx: &mut Context<Self>,
20424    ) {
20425        let mut editor_settings = EditorSettings::get_global(cx).clone();
20426        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20427        EditorSettings::override_global(editor_settings, cx);
20428    }
20429
20430    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20431        if let Some(show_line_numbers) = self.show_line_numbers {
20432            return show_line_numbers;
20433        }
20434        EditorSettings::get_global(cx).gutter.line_numbers
20435    }
20436
20437    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20438        match (
20439            self.use_relative_line_numbers,
20440            EditorSettings::get_global(cx).relative_line_numbers,
20441        ) {
20442            (None, setting) => setting,
20443            (Some(false), _) => RelativeLineNumbers::Disabled,
20444            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20445            (Some(true), _) => RelativeLineNumbers::Enabled,
20446        }
20447    }
20448
20449    pub fn toggle_relative_line_numbers(
20450        &mut self,
20451        _: &ToggleRelativeLineNumbers,
20452        _: &mut Window,
20453        cx: &mut Context<Self>,
20454    ) {
20455        let is_relative = self.relative_line_numbers(cx);
20456        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20457    }
20458
20459    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20460        self.use_relative_line_numbers = is_relative;
20461        cx.notify();
20462    }
20463
20464    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20465        self.show_gutter = show_gutter;
20466        cx.notify();
20467    }
20468
20469    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20470        self.show_scrollbars = ScrollbarAxes {
20471            horizontal: show,
20472            vertical: show,
20473        };
20474        cx.notify();
20475    }
20476
20477    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20478        self.show_scrollbars.vertical = show;
20479        cx.notify();
20480    }
20481
20482    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20483        self.show_scrollbars.horizontal = show;
20484        cx.notify();
20485    }
20486
20487    pub fn set_minimap_visibility(
20488        &mut self,
20489        minimap_visibility: MinimapVisibility,
20490        window: &mut Window,
20491        cx: &mut Context<Self>,
20492    ) {
20493        if self.minimap_visibility != minimap_visibility {
20494            if minimap_visibility.visible() && self.minimap.is_none() {
20495                let minimap_settings = EditorSettings::get_global(cx).minimap;
20496                self.minimap =
20497                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20498            }
20499            self.minimap_visibility = minimap_visibility;
20500            cx.notify();
20501        }
20502    }
20503
20504    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20505        self.set_show_scrollbars(false, cx);
20506        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20507    }
20508
20509    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20510        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20511    }
20512
20513    /// Normally the text in full mode and auto height editors is padded on the
20514    /// left side by roughly half a character width for improved hit testing.
20515    ///
20516    /// Use this method to disable this for cases where this is not wanted (e.g.
20517    /// if you want to align the editor text with some other text above or below)
20518    /// or if you want to add this padding to single-line editors.
20519    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20520        self.offset_content = offset_content;
20521        cx.notify();
20522    }
20523
20524    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20525        self.show_line_numbers = Some(show_line_numbers);
20526        cx.notify();
20527    }
20528
20529    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20530        self.disable_expand_excerpt_buttons = true;
20531        cx.notify();
20532    }
20533
20534    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20535        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20536        cx.notify();
20537    }
20538
20539    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20540        self.show_code_actions = Some(show_code_actions);
20541        cx.notify();
20542    }
20543
20544    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20545        self.show_runnables = Some(show_runnables);
20546        cx.notify();
20547    }
20548
20549    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20550        self.show_breakpoints = Some(show_breakpoints);
20551        cx.notify();
20552    }
20553
20554    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20555        if self.display_map.read(cx).masked != masked {
20556            self.display_map.update(cx, |map, _| map.masked = masked);
20557        }
20558        cx.notify()
20559    }
20560
20561    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20562        self.show_wrap_guides = Some(show_wrap_guides);
20563        cx.notify();
20564    }
20565
20566    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20567        self.show_indent_guides = Some(show_indent_guides);
20568        cx.notify();
20569    }
20570
20571    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20572        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20573            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20574                && let Some(dir) = file.abs_path(cx).parent()
20575            {
20576                return Some(dir.to_owned());
20577            }
20578        }
20579
20580        None
20581    }
20582
20583    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20584        self.active_excerpt(cx)?
20585            .1
20586            .read(cx)
20587            .file()
20588            .and_then(|f| f.as_local())
20589    }
20590
20591    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20592        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20593            let buffer = buffer.read(cx);
20594            if let Some(project_path) = buffer.project_path(cx) {
20595                let project = self.project()?.read(cx);
20596                project.absolute_path(&project_path, cx)
20597            } else {
20598                buffer
20599                    .file()
20600                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20601            }
20602        })
20603    }
20604
20605    pub fn reveal_in_finder(
20606        &mut self,
20607        _: &RevealInFileManager,
20608        _window: &mut Window,
20609        cx: &mut Context<Self>,
20610    ) {
20611        if let Some(target) = self.target_file(cx) {
20612            cx.reveal_path(&target.abs_path(cx));
20613        }
20614    }
20615
20616    pub fn copy_path(
20617        &mut self,
20618        _: &zed_actions::workspace::CopyPath,
20619        _window: &mut Window,
20620        cx: &mut Context<Self>,
20621    ) {
20622        if let Some(path) = self.target_file_abs_path(cx)
20623            && let Some(path) = path.to_str()
20624        {
20625            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20626        } else {
20627            cx.propagate();
20628        }
20629    }
20630
20631    pub fn copy_relative_path(
20632        &mut self,
20633        _: &zed_actions::workspace::CopyRelativePath,
20634        _window: &mut Window,
20635        cx: &mut Context<Self>,
20636    ) {
20637        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20638            let project = self.project()?.read(cx);
20639            let path = buffer.read(cx).file()?.path();
20640            let path = path.display(project.path_style(cx));
20641            Some(path)
20642        }) {
20643            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20644        } else {
20645            cx.propagate();
20646        }
20647    }
20648
20649    /// Returns the project path for the editor's buffer, if any buffer is
20650    /// opened in the editor.
20651    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20652        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20653            buffer.read(cx).project_path(cx)
20654        } else {
20655            None
20656        }
20657    }
20658
20659    // Returns true if the editor handled a go-to-line request
20660    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20661        maybe!({
20662            let breakpoint_store = self.breakpoint_store.as_ref()?;
20663
20664            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20665            else {
20666                self.clear_row_highlights::<ActiveDebugLine>();
20667                return None;
20668            };
20669
20670            let position = active_stack_frame.position;
20671            let buffer_id = position.buffer_id?;
20672            let snapshot = self
20673                .project
20674                .as_ref()?
20675                .read(cx)
20676                .buffer_for_id(buffer_id, cx)?
20677                .read(cx)
20678                .snapshot();
20679
20680            let mut handled = false;
20681            for (id, ExcerptRange { context, .. }) in
20682                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20683            {
20684                if context.start.cmp(&position, &snapshot).is_ge()
20685                    || context.end.cmp(&position, &snapshot).is_lt()
20686                {
20687                    continue;
20688                }
20689                let snapshot = self.buffer.read(cx).snapshot(cx);
20690                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20691
20692                handled = true;
20693                self.clear_row_highlights::<ActiveDebugLine>();
20694
20695                self.go_to_line::<ActiveDebugLine>(
20696                    multibuffer_anchor,
20697                    Some(cx.theme().colors().editor_debugger_active_line_background),
20698                    window,
20699                    cx,
20700                );
20701
20702                cx.notify();
20703            }
20704
20705            handled.then_some(())
20706        })
20707        .is_some()
20708    }
20709
20710    pub fn copy_file_name_without_extension(
20711        &mut self,
20712        _: &CopyFileNameWithoutExtension,
20713        _: &mut Window,
20714        cx: &mut Context<Self>,
20715    ) {
20716        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20717            let file = buffer.read(cx).file()?;
20718            file.path().file_stem()
20719        }) {
20720            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20721        }
20722    }
20723
20724    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20725        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20726            let file = buffer.read(cx).file()?;
20727            Some(file.file_name(cx))
20728        }) {
20729            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20730        }
20731    }
20732
20733    pub fn toggle_git_blame(
20734        &mut self,
20735        _: &::git::Blame,
20736        window: &mut Window,
20737        cx: &mut Context<Self>,
20738    ) {
20739        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20740
20741        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20742            self.start_git_blame(true, window, cx);
20743        }
20744
20745        cx.notify();
20746    }
20747
20748    pub fn toggle_git_blame_inline(
20749        &mut self,
20750        _: &ToggleGitBlameInline,
20751        window: &mut Window,
20752        cx: &mut Context<Self>,
20753    ) {
20754        self.toggle_git_blame_inline_internal(true, window, cx);
20755        cx.notify();
20756    }
20757
20758    pub fn open_git_blame_commit(
20759        &mut self,
20760        _: &OpenGitBlameCommit,
20761        window: &mut Window,
20762        cx: &mut Context<Self>,
20763    ) {
20764        self.open_git_blame_commit_internal(window, cx);
20765    }
20766
20767    fn open_git_blame_commit_internal(
20768        &mut self,
20769        window: &mut Window,
20770        cx: &mut Context<Self>,
20771    ) -> Option<()> {
20772        let blame = self.blame.as_ref()?;
20773        let snapshot = self.snapshot(window, cx);
20774        let cursor = self
20775            .selections
20776            .newest::<Point>(&snapshot.display_snapshot)
20777            .head();
20778        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20779        let (_, blame_entry) = blame
20780            .update(cx, |blame, cx| {
20781                blame
20782                    .blame_for_rows(
20783                        &[RowInfo {
20784                            buffer_id: Some(buffer.remote_id()),
20785                            buffer_row: Some(point.row),
20786                            ..Default::default()
20787                        }],
20788                        cx,
20789                    )
20790                    .next()
20791            })
20792            .flatten()?;
20793        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20794        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20795        let workspace = self.workspace()?.downgrade();
20796        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20797        None
20798    }
20799
20800    pub fn git_blame_inline_enabled(&self) -> bool {
20801        self.git_blame_inline_enabled
20802    }
20803
20804    pub fn toggle_selection_menu(
20805        &mut self,
20806        _: &ToggleSelectionMenu,
20807        _: &mut Window,
20808        cx: &mut Context<Self>,
20809    ) {
20810        self.show_selection_menu = self
20811            .show_selection_menu
20812            .map(|show_selections_menu| !show_selections_menu)
20813            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20814
20815        cx.notify();
20816    }
20817
20818    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20819        self.show_selection_menu
20820            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20821    }
20822
20823    fn start_git_blame(
20824        &mut self,
20825        user_triggered: bool,
20826        window: &mut Window,
20827        cx: &mut Context<Self>,
20828    ) {
20829        if let Some(project) = self.project() {
20830            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20831                && buffer.read(cx).file().is_none()
20832            {
20833                return;
20834            }
20835
20836            let focused = self.focus_handle(cx).contains_focused(window, cx);
20837
20838            let project = project.clone();
20839            let blame = cx
20840                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20841            self.blame_subscription =
20842                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20843            self.blame = Some(blame);
20844        }
20845    }
20846
20847    fn toggle_git_blame_inline_internal(
20848        &mut self,
20849        user_triggered: bool,
20850        window: &mut Window,
20851        cx: &mut Context<Self>,
20852    ) {
20853        if self.git_blame_inline_enabled {
20854            self.git_blame_inline_enabled = false;
20855            self.show_git_blame_inline = false;
20856            self.show_git_blame_inline_delay_task.take();
20857        } else {
20858            self.git_blame_inline_enabled = true;
20859            self.start_git_blame_inline(user_triggered, window, cx);
20860        }
20861
20862        cx.notify();
20863    }
20864
20865    fn start_git_blame_inline(
20866        &mut self,
20867        user_triggered: bool,
20868        window: &mut Window,
20869        cx: &mut Context<Self>,
20870    ) {
20871        self.start_git_blame(user_triggered, window, cx);
20872
20873        if ProjectSettings::get_global(cx)
20874            .git
20875            .inline_blame_delay()
20876            .is_some()
20877        {
20878            self.start_inline_blame_timer(window, cx);
20879        } else {
20880            self.show_git_blame_inline = true
20881        }
20882    }
20883
20884    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20885        self.blame.as_ref()
20886    }
20887
20888    pub fn show_git_blame_gutter(&self) -> bool {
20889        self.show_git_blame_gutter
20890    }
20891
20892    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20893        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20894    }
20895
20896    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20897        self.show_git_blame_inline
20898            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20899            && !self.newest_selection_head_on_empty_line(cx)
20900            && self.has_blame_entries(cx)
20901    }
20902
20903    fn has_blame_entries(&self, cx: &App) -> bool {
20904        self.blame()
20905            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20906    }
20907
20908    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20909        let cursor_anchor = self.selections.newest_anchor().head();
20910
20911        let snapshot = self.buffer.read(cx).snapshot(cx);
20912        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20913
20914        snapshot.line_len(buffer_row) == 0
20915    }
20916
20917    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20918        let buffer_and_selection = maybe!({
20919            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20920            let selection_range = selection.range();
20921
20922            let multi_buffer = self.buffer().read(cx);
20923            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20924            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20925
20926            let (buffer, range, _) = if selection.reversed {
20927                buffer_ranges.first()
20928            } else {
20929                buffer_ranges.last()
20930            }?;
20931
20932            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
20933            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
20934
20935            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
20936                let selection = start_row_in_buffer..end_row_in_buffer;
20937
20938                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
20939            };
20940
20941            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
20942
20943            Some((
20944                multi_buffer.buffer(buffer.remote_id()).unwrap(),
20945                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, buffer)
20946                    ..buffer_diff_snapshot.row_to_base_text_row(end_row_in_buffer, buffer),
20947            ))
20948        });
20949
20950        let Some((buffer, selection)) = buffer_and_selection else {
20951            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20952        };
20953
20954        let Some(project) = self.project() else {
20955            return Task::ready(Err(anyhow!("editor does not have project")));
20956        };
20957
20958        project.update(cx, |project, cx| {
20959            project.get_permalink_to_line(&buffer, selection, cx)
20960        })
20961    }
20962
20963    pub fn copy_permalink_to_line(
20964        &mut self,
20965        _: &CopyPermalinkToLine,
20966        window: &mut Window,
20967        cx: &mut Context<Self>,
20968    ) {
20969        let permalink_task = self.get_permalink_to_line(cx);
20970        let workspace = self.workspace();
20971
20972        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20973            Ok(permalink) => {
20974                cx.update(|_, cx| {
20975                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20976                })
20977                .ok();
20978            }
20979            Err(err) => {
20980                let message = format!("Failed to copy permalink: {err}");
20981
20982                anyhow::Result::<()>::Err(err).log_err();
20983
20984                if let Some(workspace) = workspace {
20985                    workspace
20986                        .update_in(cx, |workspace, _, cx| {
20987                            struct CopyPermalinkToLine;
20988
20989                            workspace.show_toast(
20990                                Toast::new(
20991                                    NotificationId::unique::<CopyPermalinkToLine>(),
20992                                    message,
20993                                ),
20994                                cx,
20995                            )
20996                        })
20997                        .ok();
20998                }
20999            }
21000        })
21001        .detach();
21002    }
21003
21004    pub fn copy_file_location(
21005        &mut self,
21006        _: &CopyFileLocation,
21007        _: &mut Window,
21008        cx: &mut Context<Self>,
21009    ) {
21010        let selection = self
21011            .selections
21012            .newest::<Point>(&self.display_snapshot(cx))
21013            .start
21014            .row
21015            + 1;
21016        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21017            let project = self.project()?.read(cx);
21018            let file = buffer.read(cx).file()?;
21019            let path = file.path().display(project.path_style(cx));
21020
21021            Some(format!("{path}:{selection}"))
21022        }) {
21023            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21024        }
21025    }
21026
21027    pub fn open_permalink_to_line(
21028        &mut self,
21029        _: &OpenPermalinkToLine,
21030        window: &mut Window,
21031        cx: &mut Context<Self>,
21032    ) {
21033        let permalink_task = self.get_permalink_to_line(cx);
21034        let workspace = self.workspace();
21035
21036        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21037            Ok(permalink) => {
21038                cx.update(|_, cx| {
21039                    cx.open_url(permalink.as_ref());
21040                })
21041                .ok();
21042            }
21043            Err(err) => {
21044                let message = format!("Failed to open permalink: {err}");
21045
21046                anyhow::Result::<()>::Err(err).log_err();
21047
21048                if let Some(workspace) = workspace {
21049                    workspace
21050                        .update(cx, |workspace, cx| {
21051                            struct OpenPermalinkToLine;
21052
21053                            workspace.show_toast(
21054                                Toast::new(
21055                                    NotificationId::unique::<OpenPermalinkToLine>(),
21056                                    message,
21057                                ),
21058                                cx,
21059                            )
21060                        })
21061                        .ok();
21062                }
21063            }
21064        })
21065        .detach();
21066    }
21067
21068    pub fn insert_uuid_v4(
21069        &mut self,
21070        _: &InsertUuidV4,
21071        window: &mut Window,
21072        cx: &mut Context<Self>,
21073    ) {
21074        self.insert_uuid(UuidVersion::V4, window, cx);
21075    }
21076
21077    pub fn insert_uuid_v7(
21078        &mut self,
21079        _: &InsertUuidV7,
21080        window: &mut Window,
21081        cx: &mut Context<Self>,
21082    ) {
21083        self.insert_uuid(UuidVersion::V7, window, cx);
21084    }
21085
21086    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21087        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21088        self.transact(window, cx, |this, window, cx| {
21089            let edits = this
21090                .selections
21091                .all::<Point>(&this.display_snapshot(cx))
21092                .into_iter()
21093                .map(|selection| {
21094                    let uuid = match version {
21095                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21096                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21097                    };
21098
21099                    (selection.range(), uuid.to_string())
21100                });
21101            this.edit(edits, cx);
21102            this.refresh_edit_prediction(true, false, window, cx);
21103        });
21104    }
21105
21106    pub fn open_selections_in_multibuffer(
21107        &mut self,
21108        _: &OpenSelectionsInMultibuffer,
21109        window: &mut Window,
21110        cx: &mut Context<Self>,
21111    ) {
21112        let multibuffer = self.buffer.read(cx);
21113
21114        let Some(buffer) = multibuffer.as_singleton() else {
21115            return;
21116        };
21117
21118        let Some(workspace) = self.workspace() else {
21119            return;
21120        };
21121
21122        let title = multibuffer.title(cx).to_string();
21123
21124        let locations = self
21125            .selections
21126            .all_anchors(&self.display_snapshot(cx))
21127            .iter()
21128            .map(|selection| {
21129                (
21130                    buffer.clone(),
21131                    (selection.start.text_anchor..selection.end.text_anchor)
21132                        .to_point(buffer.read(cx)),
21133                )
21134            })
21135            .into_group_map();
21136
21137        cx.spawn_in(window, async move |_, cx| {
21138            workspace.update_in(cx, |workspace, window, cx| {
21139                Self::open_locations_in_multibuffer(
21140                    workspace,
21141                    locations,
21142                    format!("Selections for '{title}'"),
21143                    false,
21144                    false,
21145                    MultibufferSelectionMode::All,
21146                    window,
21147                    cx,
21148                );
21149            })
21150        })
21151        .detach();
21152    }
21153
21154    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21155    /// last highlight added will be used.
21156    ///
21157    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21158    pub fn highlight_rows<T: 'static>(
21159        &mut self,
21160        range: Range<Anchor>,
21161        color: Hsla,
21162        options: RowHighlightOptions,
21163        cx: &mut Context<Self>,
21164    ) {
21165        let snapshot = self.buffer().read(cx).snapshot(cx);
21166        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21167        let ix = row_highlights.binary_search_by(|highlight| {
21168            Ordering::Equal
21169                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21170                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21171        });
21172
21173        if let Err(mut ix) = ix {
21174            let index = post_inc(&mut self.highlight_order);
21175
21176            // If this range intersects with the preceding highlight, then merge it with
21177            // the preceding highlight. Otherwise insert a new highlight.
21178            let mut merged = false;
21179            if ix > 0 {
21180                let prev_highlight = &mut row_highlights[ix - 1];
21181                if prev_highlight
21182                    .range
21183                    .end
21184                    .cmp(&range.start, &snapshot)
21185                    .is_ge()
21186                {
21187                    ix -= 1;
21188                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21189                        prev_highlight.range.end = range.end;
21190                    }
21191                    merged = true;
21192                    prev_highlight.index = index;
21193                    prev_highlight.color = color;
21194                    prev_highlight.options = options;
21195                }
21196            }
21197
21198            if !merged {
21199                row_highlights.insert(
21200                    ix,
21201                    RowHighlight {
21202                        range,
21203                        index,
21204                        color,
21205                        options,
21206                        type_id: TypeId::of::<T>(),
21207                    },
21208                );
21209            }
21210
21211            // If any of the following highlights intersect with this one, merge them.
21212            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21213                let highlight = &row_highlights[ix];
21214                if next_highlight
21215                    .range
21216                    .start
21217                    .cmp(&highlight.range.end, &snapshot)
21218                    .is_le()
21219                {
21220                    if next_highlight
21221                        .range
21222                        .end
21223                        .cmp(&highlight.range.end, &snapshot)
21224                        .is_gt()
21225                    {
21226                        row_highlights[ix].range.end = next_highlight.range.end;
21227                    }
21228                    row_highlights.remove(ix + 1);
21229                } else {
21230                    break;
21231                }
21232            }
21233        }
21234    }
21235
21236    /// Remove any highlighted row ranges of the given type that intersect the
21237    /// given ranges.
21238    pub fn remove_highlighted_rows<T: 'static>(
21239        &mut self,
21240        ranges_to_remove: Vec<Range<Anchor>>,
21241        cx: &mut Context<Self>,
21242    ) {
21243        let snapshot = self.buffer().read(cx).snapshot(cx);
21244        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21245        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21246        row_highlights.retain(|highlight| {
21247            while let Some(range_to_remove) = ranges_to_remove.peek() {
21248                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21249                    Ordering::Less | Ordering::Equal => {
21250                        ranges_to_remove.next();
21251                    }
21252                    Ordering::Greater => {
21253                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21254                            Ordering::Less | Ordering::Equal => {
21255                                return false;
21256                            }
21257                            Ordering::Greater => break,
21258                        }
21259                    }
21260                }
21261            }
21262
21263            true
21264        })
21265    }
21266
21267    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21268    pub fn clear_row_highlights<T: 'static>(&mut self) {
21269        self.highlighted_rows.remove(&TypeId::of::<T>());
21270    }
21271
21272    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21273    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21274        self.highlighted_rows
21275            .get(&TypeId::of::<T>())
21276            .map_or(&[] as &[_], |vec| vec.as_slice())
21277            .iter()
21278            .map(|highlight| (highlight.range.clone(), highlight.color))
21279    }
21280
21281    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21282    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21283    /// Allows to ignore certain kinds of highlights.
21284    pub fn highlighted_display_rows(
21285        &self,
21286        window: &mut Window,
21287        cx: &mut App,
21288    ) -> BTreeMap<DisplayRow, LineHighlight> {
21289        let snapshot = self.snapshot(window, cx);
21290        let mut used_highlight_orders = HashMap::default();
21291        self.highlighted_rows
21292            .iter()
21293            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21294            .fold(
21295                BTreeMap::<DisplayRow, LineHighlight>::new(),
21296                |mut unique_rows, highlight| {
21297                    let start = highlight.range.start.to_display_point(&snapshot);
21298                    let end = highlight.range.end.to_display_point(&snapshot);
21299                    let start_row = start.row().0;
21300                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21301                    {
21302                        end.row().0.saturating_sub(1)
21303                    } else {
21304                        end.row().0
21305                    };
21306                    for row in start_row..=end_row {
21307                        let used_index =
21308                            used_highlight_orders.entry(row).or_insert(highlight.index);
21309                        if highlight.index >= *used_index {
21310                            *used_index = highlight.index;
21311                            unique_rows.insert(
21312                                DisplayRow(row),
21313                                LineHighlight {
21314                                    include_gutter: highlight.options.include_gutter,
21315                                    border: None,
21316                                    background: highlight.color.into(),
21317                                    type_id: Some(highlight.type_id),
21318                                },
21319                            );
21320                        }
21321                    }
21322                    unique_rows
21323                },
21324            )
21325    }
21326
21327    pub fn highlighted_display_row_for_autoscroll(
21328        &self,
21329        snapshot: &DisplaySnapshot,
21330    ) -> Option<DisplayRow> {
21331        self.highlighted_rows
21332            .values()
21333            .flat_map(|highlighted_rows| highlighted_rows.iter())
21334            .filter_map(|highlight| {
21335                if highlight.options.autoscroll {
21336                    Some(highlight.range.start.to_display_point(snapshot).row())
21337                } else {
21338                    None
21339                }
21340            })
21341            .min()
21342    }
21343
21344    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21345        self.highlight_background::<SearchWithinRange>(
21346            ranges,
21347            |_, colors| colors.colors().editor_document_highlight_read_background,
21348            cx,
21349        )
21350    }
21351
21352    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21353        self.breadcrumb_header = Some(new_header);
21354    }
21355
21356    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21357        self.clear_background_highlights::<SearchWithinRange>(cx);
21358    }
21359
21360    pub fn highlight_background<T: 'static>(
21361        &mut self,
21362        ranges: &[Range<Anchor>],
21363        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21364        cx: &mut Context<Self>,
21365    ) {
21366        self.background_highlights.insert(
21367            HighlightKey::Type(TypeId::of::<T>()),
21368            (Arc::new(color_fetcher), Arc::from(ranges)),
21369        );
21370        self.scrollbar_marker_state.dirty = true;
21371        cx.notify();
21372    }
21373
21374    pub fn highlight_background_key<T: 'static>(
21375        &mut self,
21376        key: usize,
21377        ranges: &[Range<Anchor>],
21378        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21379        cx: &mut Context<Self>,
21380    ) {
21381        self.background_highlights.insert(
21382            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21383            (Arc::new(color_fetcher), Arc::from(ranges)),
21384        );
21385        self.scrollbar_marker_state.dirty = true;
21386        cx.notify();
21387    }
21388
21389    pub fn clear_background_highlights<T: 'static>(
21390        &mut self,
21391        cx: &mut Context<Self>,
21392    ) -> Option<BackgroundHighlight> {
21393        let text_highlights = self
21394            .background_highlights
21395            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21396        if !text_highlights.1.is_empty() {
21397            self.scrollbar_marker_state.dirty = true;
21398            cx.notify();
21399        }
21400        Some(text_highlights)
21401    }
21402
21403    pub fn highlight_gutter<T: 'static>(
21404        &mut self,
21405        ranges: impl Into<Vec<Range<Anchor>>>,
21406        color_fetcher: fn(&App) -> Hsla,
21407        cx: &mut Context<Self>,
21408    ) {
21409        self.gutter_highlights
21410            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21411        cx.notify();
21412    }
21413
21414    pub fn clear_gutter_highlights<T: 'static>(
21415        &mut self,
21416        cx: &mut Context<Self>,
21417    ) -> Option<GutterHighlight> {
21418        cx.notify();
21419        self.gutter_highlights.remove(&TypeId::of::<T>())
21420    }
21421
21422    pub fn insert_gutter_highlight<T: 'static>(
21423        &mut self,
21424        range: Range<Anchor>,
21425        color_fetcher: fn(&App) -> Hsla,
21426        cx: &mut Context<Self>,
21427    ) {
21428        let snapshot = self.buffer().read(cx).snapshot(cx);
21429        let mut highlights = self
21430            .gutter_highlights
21431            .remove(&TypeId::of::<T>())
21432            .map(|(_, highlights)| highlights)
21433            .unwrap_or_default();
21434        let ix = highlights.binary_search_by(|highlight| {
21435            Ordering::Equal
21436                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21437                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21438        });
21439        if let Err(ix) = ix {
21440            highlights.insert(ix, range);
21441        }
21442        self.gutter_highlights
21443            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21444    }
21445
21446    pub fn remove_gutter_highlights<T: 'static>(
21447        &mut self,
21448        ranges_to_remove: Vec<Range<Anchor>>,
21449        cx: &mut Context<Self>,
21450    ) {
21451        let snapshot = self.buffer().read(cx).snapshot(cx);
21452        let Some((color_fetcher, mut gutter_highlights)) =
21453            self.gutter_highlights.remove(&TypeId::of::<T>())
21454        else {
21455            return;
21456        };
21457        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21458        gutter_highlights.retain(|highlight| {
21459            while let Some(range_to_remove) = ranges_to_remove.peek() {
21460                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21461                    Ordering::Less | Ordering::Equal => {
21462                        ranges_to_remove.next();
21463                    }
21464                    Ordering::Greater => {
21465                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21466                            Ordering::Less | Ordering::Equal => {
21467                                return false;
21468                            }
21469                            Ordering::Greater => break,
21470                        }
21471                    }
21472                }
21473            }
21474
21475            true
21476        });
21477        self.gutter_highlights
21478            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21479    }
21480
21481    #[cfg(feature = "test-support")]
21482    pub fn all_text_highlights(
21483        &self,
21484        window: &mut Window,
21485        cx: &mut Context<Self>,
21486    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21487        let snapshot = self.snapshot(window, cx);
21488        self.display_map.update(cx, |display_map, _| {
21489            display_map
21490                .all_text_highlights()
21491                .map(|highlight| {
21492                    let (style, ranges) = highlight.as_ref();
21493                    (
21494                        *style,
21495                        ranges
21496                            .iter()
21497                            .map(|range| range.clone().to_display_points(&snapshot))
21498                            .collect(),
21499                    )
21500                })
21501                .collect()
21502        })
21503    }
21504
21505    #[cfg(feature = "test-support")]
21506    pub fn all_text_background_highlights(
21507        &self,
21508        window: &mut Window,
21509        cx: &mut Context<Self>,
21510    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21511        let snapshot = self.snapshot(window, cx);
21512        let buffer = &snapshot.buffer_snapshot();
21513        let start = buffer.anchor_before(MultiBufferOffset(0));
21514        let end = buffer.anchor_after(buffer.len());
21515        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21516    }
21517
21518    #[cfg(any(test, feature = "test-support"))]
21519    pub fn sorted_background_highlights_in_range(
21520        &self,
21521        search_range: Range<Anchor>,
21522        display_snapshot: &DisplaySnapshot,
21523        theme: &Theme,
21524    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21525        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21526        res.sort_by(|a, b| {
21527            a.0.start
21528                .cmp(&b.0.start)
21529                .then_with(|| a.0.end.cmp(&b.0.end))
21530                .then_with(|| a.1.cmp(&b.1))
21531        });
21532        res
21533    }
21534
21535    #[cfg(feature = "test-support")]
21536    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21537        let snapshot = self.buffer().read(cx).snapshot(cx);
21538
21539        let highlights = self
21540            .background_highlights
21541            .get(&HighlightKey::Type(TypeId::of::<
21542                items::BufferSearchHighlights,
21543            >()));
21544
21545        if let Some((_color, ranges)) = highlights {
21546            ranges
21547                .iter()
21548                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21549                .collect_vec()
21550        } else {
21551            vec![]
21552        }
21553    }
21554
21555    fn document_highlights_for_position<'a>(
21556        &'a self,
21557        position: Anchor,
21558        buffer: &'a MultiBufferSnapshot,
21559    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21560        let read_highlights = self
21561            .background_highlights
21562            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21563            .map(|h| &h.1);
21564        let write_highlights = self
21565            .background_highlights
21566            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21567            .map(|h| &h.1);
21568        let left_position = position.bias_left(buffer);
21569        let right_position = position.bias_right(buffer);
21570        read_highlights
21571            .into_iter()
21572            .chain(write_highlights)
21573            .flat_map(move |ranges| {
21574                let start_ix = match ranges.binary_search_by(|probe| {
21575                    let cmp = probe.end.cmp(&left_position, buffer);
21576                    if cmp.is_ge() {
21577                        Ordering::Greater
21578                    } else {
21579                        Ordering::Less
21580                    }
21581                }) {
21582                    Ok(i) | Err(i) => i,
21583                };
21584
21585                ranges[start_ix..]
21586                    .iter()
21587                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21588            })
21589    }
21590
21591    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21592        self.background_highlights
21593            .get(&HighlightKey::Type(TypeId::of::<T>()))
21594            .is_some_and(|(_, highlights)| !highlights.is_empty())
21595    }
21596
21597    /// Returns all background highlights for a given range.
21598    ///
21599    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21600    pub fn background_highlights_in_range(
21601        &self,
21602        search_range: Range<Anchor>,
21603        display_snapshot: &DisplaySnapshot,
21604        theme: &Theme,
21605    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21606        let mut results = Vec::new();
21607        for (color_fetcher, ranges) in self.background_highlights.values() {
21608            let start_ix = match ranges.binary_search_by(|probe| {
21609                let cmp = probe
21610                    .end
21611                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21612                if cmp.is_gt() {
21613                    Ordering::Greater
21614                } else {
21615                    Ordering::Less
21616                }
21617            }) {
21618                Ok(i) | Err(i) => i,
21619            };
21620            for (index, range) in ranges[start_ix..].iter().enumerate() {
21621                if range
21622                    .start
21623                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21624                    .is_ge()
21625                {
21626                    break;
21627                }
21628
21629                let color = color_fetcher(&(start_ix + index), theme);
21630                let start = range.start.to_display_point(display_snapshot);
21631                let end = range.end.to_display_point(display_snapshot);
21632                results.push((start..end, color))
21633            }
21634        }
21635        results
21636    }
21637
21638    pub fn gutter_highlights_in_range(
21639        &self,
21640        search_range: Range<Anchor>,
21641        display_snapshot: &DisplaySnapshot,
21642        cx: &App,
21643    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21644        let mut results = Vec::new();
21645        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21646            let color = color_fetcher(cx);
21647            let start_ix = match ranges.binary_search_by(|probe| {
21648                let cmp = probe
21649                    .end
21650                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21651                if cmp.is_gt() {
21652                    Ordering::Greater
21653                } else {
21654                    Ordering::Less
21655                }
21656            }) {
21657                Ok(i) | Err(i) => i,
21658            };
21659            for range in &ranges[start_ix..] {
21660                if range
21661                    .start
21662                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21663                    .is_ge()
21664                {
21665                    break;
21666                }
21667
21668                let start = range.start.to_display_point(display_snapshot);
21669                let end = range.end.to_display_point(display_snapshot);
21670                results.push((start..end, color))
21671            }
21672        }
21673        results
21674    }
21675
21676    /// Get the text ranges corresponding to the redaction query
21677    pub fn redacted_ranges(
21678        &self,
21679        search_range: Range<Anchor>,
21680        display_snapshot: &DisplaySnapshot,
21681        cx: &App,
21682    ) -> Vec<Range<DisplayPoint>> {
21683        display_snapshot
21684            .buffer_snapshot()
21685            .redacted_ranges(search_range, |file| {
21686                if let Some(file) = file {
21687                    file.is_private()
21688                        && EditorSettings::get(
21689                            Some(SettingsLocation {
21690                                worktree_id: file.worktree_id(cx),
21691                                path: file.path().as_ref(),
21692                            }),
21693                            cx,
21694                        )
21695                        .redact_private_values
21696                } else {
21697                    false
21698                }
21699            })
21700            .map(|range| {
21701                range.start.to_display_point(display_snapshot)
21702                    ..range.end.to_display_point(display_snapshot)
21703            })
21704            .collect()
21705    }
21706
21707    pub fn highlight_text_key<T: 'static>(
21708        &mut self,
21709        key: usize,
21710        ranges: Vec<Range<Anchor>>,
21711        style: HighlightStyle,
21712        merge: bool,
21713        cx: &mut Context<Self>,
21714    ) {
21715        self.display_map.update(cx, |map, cx| {
21716            map.highlight_text(
21717                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21718                ranges,
21719                style,
21720                merge,
21721                cx,
21722            );
21723        });
21724        cx.notify();
21725    }
21726
21727    pub fn highlight_text<T: 'static>(
21728        &mut self,
21729        ranges: Vec<Range<Anchor>>,
21730        style: HighlightStyle,
21731        cx: &mut Context<Self>,
21732    ) {
21733        self.display_map.update(cx, |map, cx| {
21734            map.highlight_text(
21735                HighlightKey::Type(TypeId::of::<T>()),
21736                ranges,
21737                style,
21738                false,
21739                cx,
21740            )
21741        });
21742        cx.notify();
21743    }
21744
21745    pub fn text_highlights<'a, T: 'static>(
21746        &'a self,
21747        cx: &'a App,
21748    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21749        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21750    }
21751
21752    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21753        let cleared = self
21754            .display_map
21755            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21756        if cleared {
21757            cx.notify();
21758        }
21759    }
21760
21761    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21762        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21763            && self.focus_handle.is_focused(window)
21764    }
21765
21766    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21767        self.show_cursor_when_unfocused = is_enabled;
21768        cx.notify();
21769    }
21770
21771    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21772        cx.notify();
21773    }
21774
21775    fn on_debug_session_event(
21776        &mut self,
21777        _session: Entity<Session>,
21778        event: &SessionEvent,
21779        cx: &mut Context<Self>,
21780    ) {
21781        if let SessionEvent::InvalidateInlineValue = event {
21782            self.refresh_inline_values(cx);
21783        }
21784    }
21785
21786    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21787        let Some(project) = self.project.clone() else {
21788            return;
21789        };
21790
21791        if !self.inline_value_cache.enabled {
21792            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21793            self.splice_inlays(&inlays, Vec::new(), cx);
21794            return;
21795        }
21796
21797        let current_execution_position = self
21798            .highlighted_rows
21799            .get(&TypeId::of::<ActiveDebugLine>())
21800            .and_then(|lines| lines.last().map(|line| line.range.end));
21801
21802        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21803            let inline_values = editor
21804                .update(cx, |editor, cx| {
21805                    let Some(current_execution_position) = current_execution_position else {
21806                        return Some(Task::ready(Ok(Vec::new())));
21807                    };
21808
21809                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21810                        let snapshot = buffer.snapshot(cx);
21811
21812                        let excerpt = snapshot.excerpt_containing(
21813                            current_execution_position..current_execution_position,
21814                        )?;
21815
21816                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21817                    })?;
21818
21819                    let range =
21820                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21821
21822                    project.inline_values(buffer, range, cx)
21823                })
21824                .ok()
21825                .flatten()?
21826                .await
21827                .context("refreshing debugger inlays")
21828                .log_err()?;
21829
21830            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21831
21832            for (buffer_id, inline_value) in inline_values
21833                .into_iter()
21834                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21835            {
21836                buffer_inline_values
21837                    .entry(buffer_id)
21838                    .or_default()
21839                    .push(inline_value);
21840            }
21841
21842            editor
21843                .update(cx, |editor, cx| {
21844                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21845                    let mut new_inlays = Vec::default();
21846
21847                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21848                        let buffer_id = buffer_snapshot.remote_id();
21849                        buffer_inline_values
21850                            .get(&buffer_id)
21851                            .into_iter()
21852                            .flatten()
21853                            .for_each(|hint| {
21854                                let inlay = Inlay::debugger(
21855                                    post_inc(&mut editor.next_inlay_id),
21856                                    Anchor::in_buffer(excerpt_id, hint.position),
21857                                    hint.text(),
21858                                );
21859                                if !inlay.text().chars().contains(&'\n') {
21860                                    new_inlays.push(inlay);
21861                                }
21862                            });
21863                    }
21864
21865                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21866                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21867
21868                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21869                })
21870                .ok()?;
21871            Some(())
21872        });
21873    }
21874
21875    fn on_buffer_event(
21876        &mut self,
21877        multibuffer: &Entity<MultiBuffer>,
21878        event: &multi_buffer::Event,
21879        window: &mut Window,
21880        cx: &mut Context<Self>,
21881    ) {
21882        match event {
21883            multi_buffer::Event::Edited { edited_buffer } => {
21884                self.scrollbar_marker_state.dirty = true;
21885                self.active_indent_guides_state.dirty = true;
21886                self.refresh_active_diagnostics(cx);
21887                self.refresh_code_actions(window, cx);
21888                self.refresh_single_line_folds(window, cx);
21889                self.refresh_matching_bracket_highlights(window, cx);
21890                if self.has_active_edit_prediction() {
21891                    self.update_visible_edit_prediction(window, cx);
21892                }
21893
21894                if let Some(buffer) = edited_buffer {
21895                    if buffer.read(cx).file().is_none() {
21896                        cx.emit(EditorEvent::TitleChanged);
21897                    }
21898
21899                    if self.project.is_some() {
21900                        let buffer_id = buffer.read(cx).remote_id();
21901                        self.register_buffer(buffer_id, cx);
21902                        self.update_lsp_data(Some(buffer_id), window, cx);
21903                        self.refresh_inlay_hints(
21904                            InlayHintRefreshReason::BufferEdited(buffer_id),
21905                            cx,
21906                        );
21907                    }
21908                }
21909
21910                cx.emit(EditorEvent::BufferEdited);
21911                cx.emit(SearchEvent::MatchesInvalidated);
21912
21913                let Some(project) = &self.project else { return };
21914                let (telemetry, is_via_ssh) = {
21915                    let project = project.read(cx);
21916                    let telemetry = project.client().telemetry().clone();
21917                    let is_via_ssh = project.is_via_remote_server();
21918                    (telemetry, is_via_ssh)
21919                };
21920                telemetry.log_edit_event("editor", is_via_ssh);
21921            }
21922            multi_buffer::Event::ExcerptsAdded {
21923                buffer,
21924                predecessor,
21925                excerpts,
21926            } => {
21927                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21928                let buffer_id = buffer.read(cx).remote_id();
21929                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21930                    && let Some(project) = &self.project
21931                {
21932                    update_uncommitted_diff_for_buffer(
21933                        cx.entity(),
21934                        project,
21935                        [buffer.clone()],
21936                        self.buffer.clone(),
21937                        cx,
21938                    )
21939                    .detach();
21940                }
21941                self.update_lsp_data(Some(buffer_id), window, cx);
21942                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21943                self.colorize_brackets(false, cx);
21944                cx.emit(EditorEvent::ExcerptsAdded {
21945                    buffer: buffer.clone(),
21946                    predecessor: *predecessor,
21947                    excerpts: excerpts.clone(),
21948                });
21949            }
21950            multi_buffer::Event::ExcerptsRemoved {
21951                ids,
21952                removed_buffer_ids,
21953            } => {
21954                if let Some(inlay_hints) = &mut self.inlay_hints {
21955                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21956                }
21957                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21958                for buffer_id in removed_buffer_ids {
21959                    self.registered_buffers.remove(buffer_id);
21960                }
21961                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21962                cx.emit(EditorEvent::ExcerptsRemoved {
21963                    ids: ids.clone(),
21964                    removed_buffer_ids: removed_buffer_ids.clone(),
21965                });
21966            }
21967            multi_buffer::Event::ExcerptsEdited {
21968                excerpt_ids,
21969                buffer_ids,
21970            } => {
21971                self.display_map.update(cx, |map, cx| {
21972                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21973                });
21974                cx.emit(EditorEvent::ExcerptsEdited {
21975                    ids: excerpt_ids.clone(),
21976                });
21977            }
21978            multi_buffer::Event::ExcerptsExpanded { ids } => {
21979                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21980                self.refresh_document_highlights(cx);
21981                for id in ids {
21982                    self.fetched_tree_sitter_chunks.remove(id);
21983                }
21984                self.colorize_brackets(false, cx);
21985                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21986            }
21987            multi_buffer::Event::Reparsed(buffer_id) => {
21988                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21989                self.refresh_selected_text_highlights(true, window, cx);
21990                self.colorize_brackets(true, cx);
21991                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21992
21993                cx.emit(EditorEvent::Reparsed(*buffer_id));
21994            }
21995            multi_buffer::Event::DiffHunksToggled => {
21996                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21997            }
21998            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
21999                if !is_fresh_language {
22000                    self.registered_buffers.remove(&buffer_id);
22001                }
22002                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22003                cx.emit(EditorEvent::Reparsed(*buffer_id));
22004                cx.notify();
22005            }
22006            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22007            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22008            multi_buffer::Event::FileHandleChanged
22009            | multi_buffer::Event::Reloaded
22010            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22011            multi_buffer::Event::DiagnosticsUpdated => {
22012                self.update_diagnostics_state(window, cx);
22013            }
22014            _ => {}
22015        };
22016    }
22017
22018    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22019        if !self.diagnostics_enabled() {
22020            return;
22021        }
22022        self.refresh_active_diagnostics(cx);
22023        self.refresh_inline_diagnostics(true, window, cx);
22024        self.scrollbar_marker_state.dirty = true;
22025        cx.notify();
22026    }
22027
22028    pub fn start_temporary_diff_override(&mut self) {
22029        self.load_diff_task.take();
22030        self.temporary_diff_override = true;
22031    }
22032
22033    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22034        self.temporary_diff_override = false;
22035        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22036        self.buffer.update(cx, |buffer, cx| {
22037            buffer.set_all_diff_hunks_collapsed(cx);
22038        });
22039
22040        if let Some(project) = self.project.clone() {
22041            self.load_diff_task = Some(
22042                update_uncommitted_diff_for_buffer(
22043                    cx.entity(),
22044                    &project,
22045                    self.buffer.read(cx).all_buffers(),
22046                    self.buffer.clone(),
22047                    cx,
22048                )
22049                .shared(),
22050            );
22051        }
22052    }
22053
22054    fn on_display_map_changed(
22055        &mut self,
22056        _: Entity<DisplayMap>,
22057        _: &mut Window,
22058        cx: &mut Context<Self>,
22059    ) {
22060        cx.notify();
22061    }
22062
22063    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22064        if !self.mode.is_full() {
22065            return None;
22066        }
22067
22068        let theme_settings = theme::ThemeSettings::get_global(cx);
22069        let theme = cx.theme();
22070        let accent_colors = theme.accents().clone();
22071
22072        let accent_overrides = theme_settings
22073            .theme_overrides
22074            .get(theme.name.as_ref())
22075            .map(|theme_style| &theme_style.accents)
22076            .into_iter()
22077            .flatten()
22078            .chain(
22079                theme_settings
22080                    .experimental_theme_overrides
22081                    .as_ref()
22082                    .map(|overrides| &overrides.accents)
22083                    .into_iter()
22084                    .flatten(),
22085            )
22086            .flat_map(|accent| accent.0.clone())
22087            .collect();
22088
22089        Some(AccentData {
22090            colors: accent_colors,
22091            overrides: accent_overrides,
22092        })
22093    }
22094
22095    fn fetch_applicable_language_settings(
22096        &self,
22097        cx: &App,
22098    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22099        if !self.mode.is_full() {
22100            return HashMap::default();
22101        }
22102
22103        self.buffer().read(cx).all_buffers().into_iter().fold(
22104            HashMap::default(),
22105            |mut acc, buffer| {
22106                let buffer = buffer.read(cx);
22107                let language = buffer.language().map(|language| language.name());
22108                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22109                    let file = buffer.file();
22110                    v.insert(language_settings(language, file, cx).into_owned());
22111                }
22112                acc
22113            },
22114        )
22115    }
22116
22117    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22118        let new_language_settings = self.fetch_applicable_language_settings(cx);
22119        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22120        self.applicable_language_settings = new_language_settings;
22121
22122        let new_accents = self.fetch_accent_data(cx);
22123        let accents_changed = new_accents != self.accent_data;
22124        self.accent_data = new_accents;
22125
22126        if self.diagnostics_enabled() {
22127            let new_severity = EditorSettings::get_global(cx)
22128                .diagnostics_max_severity
22129                .unwrap_or(DiagnosticSeverity::Hint);
22130            self.set_max_diagnostics_severity(new_severity, cx);
22131        }
22132        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22133        self.update_edit_prediction_settings(cx);
22134        self.refresh_edit_prediction(true, false, window, cx);
22135        self.refresh_inline_values(cx);
22136        self.refresh_inlay_hints(
22137            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22138                self.selections.newest_anchor().head(),
22139                &self.buffer.read(cx).snapshot(cx),
22140                cx,
22141            )),
22142            cx,
22143        );
22144
22145        let old_cursor_shape = self.cursor_shape;
22146        let old_show_breadcrumbs = self.show_breadcrumbs;
22147
22148        {
22149            let editor_settings = EditorSettings::get_global(cx);
22150            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22151            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22152            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22153            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22154        }
22155
22156        if old_cursor_shape != self.cursor_shape {
22157            cx.emit(EditorEvent::CursorShapeChanged);
22158        }
22159
22160        if old_show_breadcrumbs != self.show_breadcrumbs {
22161            cx.emit(EditorEvent::BreadcrumbsChanged);
22162        }
22163
22164        let project_settings = ProjectSettings::get_global(cx);
22165        self.buffer_serialization = self
22166            .should_serialize_buffer()
22167            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22168
22169        if self.mode.is_full() {
22170            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22171            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22172            if self.show_inline_diagnostics != show_inline_diagnostics {
22173                self.show_inline_diagnostics = show_inline_diagnostics;
22174                self.refresh_inline_diagnostics(false, window, cx);
22175            }
22176
22177            if self.git_blame_inline_enabled != inline_blame_enabled {
22178                self.toggle_git_blame_inline_internal(false, window, cx);
22179            }
22180
22181            let minimap_settings = EditorSettings::get_global(cx).minimap;
22182            if self.minimap_visibility != MinimapVisibility::Disabled {
22183                if self.minimap_visibility.settings_visibility()
22184                    != minimap_settings.minimap_enabled()
22185                {
22186                    self.set_minimap_visibility(
22187                        MinimapVisibility::for_mode(self.mode(), cx),
22188                        window,
22189                        cx,
22190                    );
22191                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22192                    minimap_entity.update(cx, |minimap_editor, cx| {
22193                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22194                    })
22195                }
22196            }
22197
22198            if language_settings_changed || accents_changed {
22199                self.colorize_brackets(true, cx);
22200            }
22201
22202            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22203                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22204            }) {
22205                if !inlay_splice.is_empty() {
22206                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22207                }
22208                self.refresh_colors_for_visible_range(None, window, cx);
22209            }
22210        }
22211
22212        cx.notify();
22213    }
22214
22215    pub fn set_searchable(&mut self, searchable: bool) {
22216        self.searchable = searchable;
22217    }
22218
22219    pub fn searchable(&self) -> bool {
22220        self.searchable
22221    }
22222
22223    pub fn open_excerpts_in_split(
22224        &mut self,
22225        _: &OpenExcerptsSplit,
22226        window: &mut Window,
22227        cx: &mut Context<Self>,
22228    ) {
22229        self.open_excerpts_common(None, true, window, cx)
22230    }
22231
22232    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22233        self.open_excerpts_common(None, false, window, cx)
22234    }
22235
22236    fn open_excerpts_common(
22237        &mut self,
22238        jump_data: Option<JumpData>,
22239        split: bool,
22240        window: &mut Window,
22241        cx: &mut Context<Self>,
22242    ) {
22243        let Some(workspace) = self.workspace() else {
22244            cx.propagate();
22245            return;
22246        };
22247
22248        if self.buffer.read(cx).is_singleton() {
22249            cx.propagate();
22250            return;
22251        }
22252
22253        let mut new_selections_by_buffer = HashMap::default();
22254        match &jump_data {
22255            Some(JumpData::MultiBufferPoint {
22256                excerpt_id,
22257                position,
22258                anchor,
22259                line_offset_from_top,
22260            }) => {
22261                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22262                if let Some(buffer) = multi_buffer_snapshot
22263                    .buffer_id_for_excerpt(*excerpt_id)
22264                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22265                {
22266                    let buffer_snapshot = buffer.read(cx).snapshot();
22267                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22268                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22269                    } else {
22270                        buffer_snapshot.clip_point(*position, Bias::Left)
22271                    };
22272                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22273                    new_selections_by_buffer.insert(
22274                        buffer,
22275                        (
22276                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22277                            Some(*line_offset_from_top),
22278                        ),
22279                    );
22280                }
22281            }
22282            Some(JumpData::MultiBufferRow {
22283                row,
22284                line_offset_from_top,
22285            }) => {
22286                let point = MultiBufferPoint::new(row.0, 0);
22287                if let Some((buffer, buffer_point, _)) =
22288                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22289                {
22290                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22291                    new_selections_by_buffer
22292                        .entry(buffer)
22293                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22294                        .0
22295                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22296                }
22297            }
22298            None => {
22299                let selections = self
22300                    .selections
22301                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22302                let multi_buffer = self.buffer.read(cx);
22303                for selection in selections {
22304                    for (snapshot, range, _, anchor) in multi_buffer
22305                        .snapshot(cx)
22306                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22307                    {
22308                        if let Some(anchor) = anchor {
22309                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22310                            else {
22311                                continue;
22312                            };
22313                            let offset = text::ToOffset::to_offset(
22314                                &anchor.text_anchor,
22315                                &buffer_handle.read(cx).snapshot(),
22316                            );
22317                            let range = BufferOffset(offset)..BufferOffset(offset);
22318                            new_selections_by_buffer
22319                                .entry(buffer_handle)
22320                                .or_insert((Vec::new(), None))
22321                                .0
22322                                .push(range)
22323                        } else {
22324                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22325                            else {
22326                                continue;
22327                            };
22328                            new_selections_by_buffer
22329                                .entry(buffer_handle)
22330                                .or_insert((Vec::new(), None))
22331                                .0
22332                                .push(range)
22333                        }
22334                    }
22335                }
22336            }
22337        }
22338
22339        new_selections_by_buffer
22340            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22341
22342        if new_selections_by_buffer.is_empty() {
22343            return;
22344        }
22345
22346        // We defer the pane interaction because we ourselves are a workspace item
22347        // and activating a new item causes the pane to call a method on us reentrantly,
22348        // which panics if we're on the stack.
22349        window.defer(cx, move |window, cx| {
22350            workspace.update(cx, |workspace, cx| {
22351                let pane = if split {
22352                    workspace.adjacent_pane(window, cx)
22353                } else {
22354                    workspace.active_pane().clone()
22355                };
22356
22357                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22358                    let buffer_read = buffer.read(cx);
22359                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22360                        (true, project::File::from_dyn(Some(file)).is_some())
22361                    } else {
22362                        (false, false)
22363                    };
22364
22365                    // If project file is none workspace.open_project_item will fail to open the excerpt
22366                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22367                    // so we check if there's a tab match in that case first
22368                    let editor = (!has_file || !is_project_file)
22369                        .then(|| {
22370                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22371                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22372                            // Instead, we try to activate the existing editor in the pane first.
22373                            let (editor, pane_item_index, pane_item_id) =
22374                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22375                                    let editor = item.downcast::<Editor>()?;
22376                                    let singleton_buffer =
22377                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22378                                    if singleton_buffer == buffer {
22379                                        Some((editor, i, item.item_id()))
22380                                    } else {
22381                                        None
22382                                    }
22383                                })?;
22384                            pane.update(cx, |pane, cx| {
22385                                pane.activate_item(pane_item_index, true, true, window, cx);
22386                                if !PreviewTabsSettings::get_global(cx)
22387                                    .enable_preview_from_multibuffer
22388                                {
22389                                    pane.unpreview_item_if_preview(pane_item_id);
22390                                }
22391                            });
22392                            Some(editor)
22393                        })
22394                        .flatten()
22395                        .unwrap_or_else(|| {
22396                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22397                                .enable_keep_preview_on_code_navigation;
22398                            let allow_new_preview =
22399                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22400                            workspace.open_project_item::<Self>(
22401                                pane.clone(),
22402                                buffer,
22403                                true,
22404                                true,
22405                                keep_old_preview,
22406                                allow_new_preview,
22407                                window,
22408                                cx,
22409                            )
22410                        });
22411
22412                    editor.update(cx, |editor, cx| {
22413                        if has_file && !is_project_file {
22414                            editor.set_read_only(true);
22415                        }
22416                        let autoscroll = match scroll_offset {
22417                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22418                            None => Autoscroll::newest(),
22419                        };
22420                        let nav_history = editor.nav_history.take();
22421                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22422                        let Some((&excerpt_id, _, buffer_snapshot)) =
22423                            multibuffer_snapshot.as_singleton()
22424                        else {
22425                            return;
22426                        };
22427                        editor.change_selections(
22428                            SelectionEffects::scroll(autoscroll),
22429                            window,
22430                            cx,
22431                            |s| {
22432                                s.select_ranges(ranges.into_iter().map(|range| {
22433                                    let range = buffer_snapshot.anchor_before(range.start)
22434                                        ..buffer_snapshot.anchor_after(range.end);
22435                                    multibuffer_snapshot
22436                                        .anchor_range_in_excerpt(excerpt_id, range)
22437                                        .unwrap()
22438                                }));
22439                            },
22440                        );
22441                        editor.nav_history = nav_history;
22442                    });
22443                }
22444            })
22445        });
22446    }
22447
22448    // Allow opening excerpts for buffers that either belong to the current project
22449    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22450    // are also supported so tests and other in-memory views keep working.
22451    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22452        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22453    }
22454
22455    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22456        let snapshot = self.buffer.read(cx).read(cx);
22457        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22458        Some(
22459            ranges
22460                .iter()
22461                .map(move |range| {
22462                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22463                })
22464                .collect(),
22465        )
22466    }
22467
22468    fn selection_replacement_ranges(
22469        &self,
22470        range: Range<MultiBufferOffsetUtf16>,
22471        cx: &mut App,
22472    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22473        let selections = self
22474            .selections
22475            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22476        let newest_selection = selections
22477            .iter()
22478            .max_by_key(|selection| selection.id)
22479            .unwrap();
22480        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22481        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22482        let snapshot = self.buffer.read(cx).read(cx);
22483        selections
22484            .into_iter()
22485            .map(|mut selection| {
22486                selection.start.0.0 =
22487                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22488                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22489                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22490                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22491            })
22492            .collect()
22493    }
22494
22495    fn report_editor_event(
22496        &self,
22497        reported_event: ReportEditorEvent,
22498        file_extension: Option<String>,
22499        cx: &App,
22500    ) {
22501        if cfg!(any(test, feature = "test-support")) {
22502            return;
22503        }
22504
22505        let Some(project) = &self.project else { return };
22506
22507        // If None, we are in a file without an extension
22508        let file = self
22509            .buffer
22510            .read(cx)
22511            .as_singleton()
22512            .and_then(|b| b.read(cx).file());
22513        let file_extension = file_extension.or(file
22514            .as_ref()
22515            .and_then(|file| Path::new(file.file_name(cx)).extension())
22516            .and_then(|e| e.to_str())
22517            .map(|a| a.to_string()));
22518
22519        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22520            .map(|vim_mode| vim_mode.0)
22521            .unwrap_or(false);
22522
22523        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22524        let copilot_enabled = edit_predictions_provider
22525            == language::language_settings::EditPredictionProvider::Copilot;
22526        let copilot_enabled_for_language = self
22527            .buffer
22528            .read(cx)
22529            .language_settings(cx)
22530            .show_edit_predictions;
22531
22532        let project = project.read(cx);
22533        let event_type = reported_event.event_type();
22534
22535        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22536            telemetry::event!(
22537                event_type,
22538                type = if auto_saved {"autosave"} else {"manual"},
22539                file_extension,
22540                vim_mode,
22541                copilot_enabled,
22542                copilot_enabled_for_language,
22543                edit_predictions_provider,
22544                is_via_ssh = project.is_via_remote_server(),
22545            );
22546        } else {
22547            telemetry::event!(
22548                event_type,
22549                file_extension,
22550                vim_mode,
22551                copilot_enabled,
22552                copilot_enabled_for_language,
22553                edit_predictions_provider,
22554                is_via_ssh = project.is_via_remote_server(),
22555            );
22556        };
22557    }
22558
22559    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22560    /// with each line being an array of {text, highlight} objects.
22561    fn copy_highlight_json(
22562        &mut self,
22563        _: &CopyHighlightJson,
22564        window: &mut Window,
22565        cx: &mut Context<Self>,
22566    ) {
22567        #[derive(Serialize)]
22568        struct Chunk<'a> {
22569            text: String,
22570            highlight: Option<&'a str>,
22571        }
22572
22573        let snapshot = self.buffer.read(cx).snapshot(cx);
22574        let range = self
22575            .selected_text_range(false, window, cx)
22576            .and_then(|selection| {
22577                if selection.range.is_empty() {
22578                    None
22579                } else {
22580                    Some(
22581                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22582                            selection.range.start,
22583                        )))
22584                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22585                                selection.range.end,
22586                            ))),
22587                    )
22588                }
22589            })
22590            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22591
22592        let chunks = snapshot.chunks(range, true);
22593        let mut lines = Vec::new();
22594        let mut line: VecDeque<Chunk> = VecDeque::new();
22595
22596        let Some(style) = self.style.as_ref() else {
22597            return;
22598        };
22599
22600        for chunk in chunks {
22601            let highlight = chunk
22602                .syntax_highlight_id
22603                .and_then(|id| id.name(&style.syntax));
22604            let mut chunk_lines = chunk.text.split('\n').peekable();
22605            while let Some(text) = chunk_lines.next() {
22606                let mut merged_with_last_token = false;
22607                if let Some(last_token) = line.back_mut()
22608                    && last_token.highlight == highlight
22609                {
22610                    last_token.text.push_str(text);
22611                    merged_with_last_token = true;
22612                }
22613
22614                if !merged_with_last_token {
22615                    line.push_back(Chunk {
22616                        text: text.into(),
22617                        highlight,
22618                    });
22619                }
22620
22621                if chunk_lines.peek().is_some() {
22622                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22623                        line.pop_front();
22624                    }
22625                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22626                        line.pop_back();
22627                    }
22628
22629                    lines.push(mem::take(&mut line));
22630                }
22631            }
22632        }
22633
22634        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22635            return;
22636        };
22637        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22638    }
22639
22640    pub fn open_context_menu(
22641        &mut self,
22642        _: &OpenContextMenu,
22643        window: &mut Window,
22644        cx: &mut Context<Self>,
22645    ) {
22646        self.request_autoscroll(Autoscroll::newest(), cx);
22647        let position = self
22648            .selections
22649            .newest_display(&self.display_snapshot(cx))
22650            .start;
22651        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22652    }
22653
22654    pub fn replay_insert_event(
22655        &mut self,
22656        text: &str,
22657        relative_utf16_range: Option<Range<isize>>,
22658        window: &mut Window,
22659        cx: &mut Context<Self>,
22660    ) {
22661        if !self.input_enabled {
22662            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22663            return;
22664        }
22665        if let Some(relative_utf16_range) = relative_utf16_range {
22666            let selections = self
22667                .selections
22668                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22669            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22670                let new_ranges = selections.into_iter().map(|range| {
22671                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22672                        range
22673                            .head()
22674                            .0
22675                            .0
22676                            .saturating_add_signed(relative_utf16_range.start),
22677                    ));
22678                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22679                        range
22680                            .head()
22681                            .0
22682                            .0
22683                            .saturating_add_signed(relative_utf16_range.end),
22684                    ));
22685                    start..end
22686                });
22687                s.select_ranges(new_ranges);
22688            });
22689        }
22690
22691        self.handle_input(text, window, cx);
22692    }
22693
22694    pub fn is_focused(&self, window: &Window) -> bool {
22695        self.focus_handle.is_focused(window)
22696    }
22697
22698    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22699        cx.emit(EditorEvent::Focused);
22700
22701        if let Some(descendant) = self
22702            .last_focused_descendant
22703            .take()
22704            .and_then(|descendant| descendant.upgrade())
22705        {
22706            window.focus(&descendant, cx);
22707        } else {
22708            if let Some(blame) = self.blame.as_ref() {
22709                blame.update(cx, GitBlame::focus)
22710            }
22711
22712            self.blink_manager.update(cx, BlinkManager::enable);
22713            self.show_cursor_names(window, cx);
22714            self.buffer.update(cx, |buffer, cx| {
22715                buffer.finalize_last_transaction(cx);
22716                if self.leader_id.is_none() {
22717                    buffer.set_active_selections(
22718                        &self.selections.disjoint_anchors_arc(),
22719                        self.selections.line_mode(),
22720                        self.cursor_shape,
22721                        cx,
22722                    );
22723                }
22724            });
22725
22726            if let Some(position_map) = self.last_position_map.clone() {
22727                EditorElement::mouse_moved(
22728                    self,
22729                    &MouseMoveEvent {
22730                        position: window.mouse_position(),
22731                        pressed_button: None,
22732                        modifiers: window.modifiers(),
22733                    },
22734                    &position_map,
22735                    window,
22736                    cx,
22737                );
22738            }
22739        }
22740    }
22741
22742    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22743        cx.emit(EditorEvent::FocusedIn)
22744    }
22745
22746    fn handle_focus_out(
22747        &mut self,
22748        event: FocusOutEvent,
22749        _window: &mut Window,
22750        cx: &mut Context<Self>,
22751    ) {
22752        if event.blurred != self.focus_handle {
22753            self.last_focused_descendant = Some(event.blurred);
22754        }
22755        self.selection_drag_state = SelectionDragState::None;
22756        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22757    }
22758
22759    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22760        self.blink_manager.update(cx, BlinkManager::disable);
22761        self.buffer
22762            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22763
22764        if let Some(blame) = self.blame.as_ref() {
22765            blame.update(cx, GitBlame::blur)
22766        }
22767        if !self.hover_state.focused(window, cx) {
22768            hide_hover(self, cx);
22769        }
22770        if !self
22771            .context_menu
22772            .borrow()
22773            .as_ref()
22774            .is_some_and(|context_menu| context_menu.focused(window, cx))
22775        {
22776            self.hide_context_menu(window, cx);
22777        }
22778        self.take_active_edit_prediction(cx);
22779        cx.emit(EditorEvent::Blurred);
22780        cx.notify();
22781    }
22782
22783    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22784        let mut pending: String = window
22785            .pending_input_keystrokes()
22786            .into_iter()
22787            .flatten()
22788            .filter_map(|keystroke| keystroke.key_char.clone())
22789            .collect();
22790
22791        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22792            pending = "".to_string();
22793        }
22794
22795        let existing_pending = self
22796            .text_highlights::<PendingInput>(cx)
22797            .map(|(_, ranges)| ranges.to_vec());
22798        if existing_pending.is_none() && pending.is_empty() {
22799            return;
22800        }
22801        let transaction =
22802            self.transact(window, cx, |this, window, cx| {
22803                let selections = this
22804                    .selections
22805                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22806                let edits = selections
22807                    .iter()
22808                    .map(|selection| (selection.end..selection.end, pending.clone()));
22809                this.edit(edits, cx);
22810                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22811                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22812                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22813                    }));
22814                });
22815                if let Some(existing_ranges) = existing_pending {
22816                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22817                    this.edit(edits, cx);
22818                }
22819            });
22820
22821        let snapshot = self.snapshot(window, cx);
22822        let ranges = self
22823            .selections
22824            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22825            .into_iter()
22826            .map(|selection| {
22827                snapshot.buffer_snapshot().anchor_after(selection.end)
22828                    ..snapshot
22829                        .buffer_snapshot()
22830                        .anchor_before(selection.end + pending.len())
22831            })
22832            .collect();
22833
22834        if pending.is_empty() {
22835            self.clear_highlights::<PendingInput>(cx);
22836        } else {
22837            self.highlight_text::<PendingInput>(
22838                ranges,
22839                HighlightStyle {
22840                    underline: Some(UnderlineStyle {
22841                        thickness: px(1.),
22842                        color: None,
22843                        wavy: false,
22844                    }),
22845                    ..Default::default()
22846                },
22847                cx,
22848            );
22849        }
22850
22851        self.ime_transaction = self.ime_transaction.or(transaction);
22852        if let Some(transaction) = self.ime_transaction {
22853            self.buffer.update(cx, |buffer, cx| {
22854                buffer.group_until_transaction(transaction, cx);
22855            });
22856        }
22857
22858        if self.text_highlights::<PendingInput>(cx).is_none() {
22859            self.ime_transaction.take();
22860        }
22861    }
22862
22863    pub fn register_action_renderer(
22864        &mut self,
22865        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22866    ) -> Subscription {
22867        let id = self.next_editor_action_id.post_inc();
22868        self.editor_actions
22869            .borrow_mut()
22870            .insert(id, Box::new(listener));
22871
22872        let editor_actions = self.editor_actions.clone();
22873        Subscription::new(move || {
22874            editor_actions.borrow_mut().remove(&id);
22875        })
22876    }
22877
22878    pub fn register_action<A: Action>(
22879        &mut self,
22880        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22881    ) -> Subscription {
22882        let id = self.next_editor_action_id.post_inc();
22883        let listener = Arc::new(listener);
22884        self.editor_actions.borrow_mut().insert(
22885            id,
22886            Box::new(move |_, window, _| {
22887                let listener = listener.clone();
22888                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22889                    let action = action.downcast_ref().unwrap();
22890                    if phase == DispatchPhase::Bubble {
22891                        listener(action, window, cx)
22892                    }
22893                })
22894            }),
22895        );
22896
22897        let editor_actions = self.editor_actions.clone();
22898        Subscription::new(move || {
22899            editor_actions.borrow_mut().remove(&id);
22900        })
22901    }
22902
22903    pub fn file_header_size(&self) -> u32 {
22904        FILE_HEADER_HEIGHT
22905    }
22906
22907    pub fn restore(
22908        &mut self,
22909        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22910        window: &mut Window,
22911        cx: &mut Context<Self>,
22912    ) {
22913        self.buffer().update(cx, |multi_buffer, cx| {
22914            for (buffer_id, changes) in revert_changes {
22915                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22916                    buffer.update(cx, |buffer, cx| {
22917                        buffer.edit(
22918                            changes
22919                                .into_iter()
22920                                .map(|(range, text)| (range, text.to_string())),
22921                            None,
22922                            cx,
22923                        );
22924                    });
22925                }
22926            }
22927        });
22928        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22929            selections.refresh()
22930        });
22931    }
22932
22933    pub fn to_pixel_point(
22934        &mut self,
22935        source: multi_buffer::Anchor,
22936        editor_snapshot: &EditorSnapshot,
22937        window: &mut Window,
22938        cx: &App,
22939    ) -> Option<gpui::Point<Pixels>> {
22940        let source_point = source.to_display_point(editor_snapshot);
22941        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
22942    }
22943
22944    pub fn display_to_pixel_point(
22945        &mut self,
22946        source: DisplayPoint,
22947        editor_snapshot: &EditorSnapshot,
22948        window: &mut Window,
22949        cx: &App,
22950    ) -> Option<gpui::Point<Pixels>> {
22951        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
22952        let text_layout_details = self.text_layout_details(window);
22953        let scroll_top = text_layout_details
22954            .scroll_anchor
22955            .scroll_position(editor_snapshot)
22956            .y;
22957
22958        if source.row().as_f64() < scroll_top.floor() {
22959            return None;
22960        }
22961        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22962        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22963        Some(gpui::Point::new(source_x, source_y))
22964    }
22965
22966    pub fn has_visible_completions_menu(&self) -> bool {
22967        !self.edit_prediction_preview_is_active()
22968            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22969                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22970            })
22971    }
22972
22973    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22974        if self.mode.is_minimap() {
22975            return;
22976        }
22977        self.addons
22978            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22979    }
22980
22981    pub fn unregister_addon<T: Addon>(&mut self) {
22982        self.addons.remove(&std::any::TypeId::of::<T>());
22983    }
22984
22985    pub fn addon<T: Addon>(&self) -> Option<&T> {
22986        let type_id = std::any::TypeId::of::<T>();
22987        self.addons
22988            .get(&type_id)
22989            .and_then(|item| item.to_any().downcast_ref::<T>())
22990    }
22991
22992    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22993        let type_id = std::any::TypeId::of::<T>();
22994        self.addons
22995            .get_mut(&type_id)
22996            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22997    }
22998
22999    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23000        let text_layout_details = self.text_layout_details(window);
23001        let style = &text_layout_details.editor_style;
23002        let font_id = window.text_system().resolve_font(&style.text.font());
23003        let font_size = style.text.font_size.to_pixels(window.rem_size());
23004        let line_height = style.text.line_height_in_pixels(window.rem_size());
23005        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23006        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23007
23008        CharacterDimensions {
23009            em_width,
23010            em_advance,
23011            line_height,
23012        }
23013    }
23014
23015    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23016        self.load_diff_task.clone()
23017    }
23018
23019    fn read_metadata_from_db(
23020        &mut self,
23021        item_id: u64,
23022        workspace_id: WorkspaceId,
23023        window: &mut Window,
23024        cx: &mut Context<Editor>,
23025    ) {
23026        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23027            && !self.mode.is_minimap()
23028            && WorkspaceSettings::get(None, cx).restore_on_startup
23029                != RestoreOnStartupBehavior::EmptyTab
23030        {
23031            let buffer_snapshot = OnceCell::new();
23032
23033            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23034                && !folds.is_empty()
23035            {
23036                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23037                self.fold_ranges(
23038                    folds
23039                        .into_iter()
23040                        .map(|(start, end)| {
23041                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23042                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23043                        })
23044                        .collect(),
23045                    false,
23046                    window,
23047                    cx,
23048                );
23049            }
23050
23051            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23052                && !selections.is_empty()
23053            {
23054                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23055                // skip adding the initial selection to selection history
23056                self.selection_history.mode = SelectionHistoryMode::Skipping;
23057                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23058                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23059                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23060                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23061                    }));
23062                });
23063                self.selection_history.mode = SelectionHistoryMode::Normal;
23064            };
23065        }
23066
23067        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23068    }
23069
23070    fn update_lsp_data(
23071        &mut self,
23072        for_buffer: Option<BufferId>,
23073        window: &mut Window,
23074        cx: &mut Context<'_, Self>,
23075    ) {
23076        self.pull_diagnostics(for_buffer, window, cx);
23077        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23078    }
23079
23080    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23081        if self.ignore_lsp_data() {
23082            return;
23083        }
23084        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23085            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23086        }
23087    }
23088
23089    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23090        if self.ignore_lsp_data() {
23091            return;
23092        }
23093
23094        if !self.registered_buffers.contains_key(&buffer_id)
23095            && let Some(project) = self.project.as_ref()
23096        {
23097            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23098                project.update(cx, |project, cx| {
23099                    self.registered_buffers.insert(
23100                        buffer_id,
23101                        project.register_buffer_with_language_servers(&buffer, cx),
23102                    );
23103                });
23104            } else {
23105                self.registered_buffers.remove(&buffer_id);
23106            }
23107        }
23108    }
23109
23110    fn ignore_lsp_data(&self) -> bool {
23111        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23112        // skip any LSP updates for it.
23113        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23114    }
23115
23116    fn create_style(&self, cx: &App) -> EditorStyle {
23117        let settings = ThemeSettings::get_global(cx);
23118
23119        let mut text_style = match self.mode {
23120            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23121                color: cx.theme().colors().editor_foreground,
23122                font_family: settings.ui_font.family.clone(),
23123                font_features: settings.ui_font.features.clone(),
23124                font_fallbacks: settings.ui_font.fallbacks.clone(),
23125                font_size: rems(0.875).into(),
23126                font_weight: settings.ui_font.weight,
23127                line_height: relative(settings.buffer_line_height.value()),
23128                ..Default::default()
23129            },
23130            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23131                color: cx.theme().colors().editor_foreground,
23132                font_family: settings.buffer_font.family.clone(),
23133                font_features: settings.buffer_font.features.clone(),
23134                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23135                font_size: settings.buffer_font_size(cx).into(),
23136                font_weight: settings.buffer_font.weight,
23137                line_height: relative(settings.buffer_line_height.value()),
23138                ..Default::default()
23139            },
23140        };
23141        if let Some(text_style_refinement) = &self.text_style_refinement {
23142            text_style.refine(text_style_refinement)
23143        }
23144
23145        let background = match self.mode {
23146            EditorMode::SingleLine => cx.theme().system().transparent,
23147            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23148            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23149            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23150        };
23151
23152        EditorStyle {
23153            background,
23154            border: cx.theme().colors().border,
23155            local_player: cx.theme().players().local(),
23156            text: text_style,
23157            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23158            syntax: cx.theme().syntax().clone(),
23159            status: cx.theme().status().clone(),
23160            inlay_hints_style: make_inlay_hints_style(cx),
23161            edit_prediction_styles: make_suggestion_styles(cx),
23162            unnecessary_code_fade: settings.unnecessary_code_fade,
23163            show_underlines: self.diagnostics_enabled(),
23164        }
23165    }
23166}
23167
23168fn edit_for_markdown_paste<'a>(
23169    buffer: &MultiBufferSnapshot,
23170    range: Range<MultiBufferOffset>,
23171    to_insert: &'a str,
23172    url: Option<url::Url>,
23173) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23174    if url.is_none() {
23175        return (range, Cow::Borrowed(to_insert));
23176    };
23177
23178    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23179
23180    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23181        Cow::Borrowed(to_insert)
23182    } else {
23183        Cow::Owned(format!("[{old_text}]({to_insert})"))
23184    };
23185    (range, new_text)
23186}
23187
23188fn process_completion_for_edit(
23189    completion: &Completion,
23190    intent: CompletionIntent,
23191    buffer: &Entity<Buffer>,
23192    cursor_position: &text::Anchor,
23193    cx: &mut Context<Editor>,
23194) -> CompletionEdit {
23195    let buffer = buffer.read(cx);
23196    let buffer_snapshot = buffer.snapshot();
23197    let (snippet, new_text) = if completion.is_snippet() {
23198        let mut snippet_source = completion.new_text.clone();
23199        // Workaround for typescript language server issues so that methods don't expand within
23200        // strings and functions with type expressions. The previous point is used because the query
23201        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23202        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23203        let previous_point = if previous_point.column > 0 {
23204            cursor_position.to_previous_offset(&buffer_snapshot)
23205        } else {
23206            cursor_position.to_offset(&buffer_snapshot)
23207        };
23208        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23209            && scope.prefers_label_for_snippet_in_completion()
23210            && let Some(label) = completion.label()
23211            && matches!(
23212                completion.kind(),
23213                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23214            )
23215        {
23216            snippet_source = label;
23217        }
23218        match Snippet::parse(&snippet_source).log_err() {
23219            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23220            None => (None, completion.new_text.clone()),
23221        }
23222    } else {
23223        (None, completion.new_text.clone())
23224    };
23225
23226    let mut range_to_replace = {
23227        let replace_range = &completion.replace_range;
23228        if let CompletionSource::Lsp {
23229            insert_range: Some(insert_range),
23230            ..
23231        } = &completion.source
23232        {
23233            debug_assert_eq!(
23234                insert_range.start, replace_range.start,
23235                "insert_range and replace_range should start at the same position"
23236            );
23237            debug_assert!(
23238                insert_range
23239                    .start
23240                    .cmp(cursor_position, &buffer_snapshot)
23241                    .is_le(),
23242                "insert_range should start before or at cursor position"
23243            );
23244            debug_assert!(
23245                replace_range
23246                    .start
23247                    .cmp(cursor_position, &buffer_snapshot)
23248                    .is_le(),
23249                "replace_range should start before or at cursor position"
23250            );
23251
23252            let should_replace = match intent {
23253                CompletionIntent::CompleteWithInsert => false,
23254                CompletionIntent::CompleteWithReplace => true,
23255                CompletionIntent::Complete | CompletionIntent::Compose => {
23256                    let insert_mode =
23257                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23258                            .completions
23259                            .lsp_insert_mode;
23260                    match insert_mode {
23261                        LspInsertMode::Insert => false,
23262                        LspInsertMode::Replace => true,
23263                        LspInsertMode::ReplaceSubsequence => {
23264                            let mut text_to_replace = buffer.chars_for_range(
23265                                buffer.anchor_before(replace_range.start)
23266                                    ..buffer.anchor_after(replace_range.end),
23267                            );
23268                            let mut current_needle = text_to_replace.next();
23269                            for haystack_ch in completion.label.text.chars() {
23270                                if let Some(needle_ch) = current_needle
23271                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23272                                {
23273                                    current_needle = text_to_replace.next();
23274                                }
23275                            }
23276                            current_needle.is_none()
23277                        }
23278                        LspInsertMode::ReplaceSuffix => {
23279                            if replace_range
23280                                .end
23281                                .cmp(cursor_position, &buffer_snapshot)
23282                                .is_gt()
23283                            {
23284                                let range_after_cursor = *cursor_position..replace_range.end;
23285                                let text_after_cursor = buffer
23286                                    .text_for_range(
23287                                        buffer.anchor_before(range_after_cursor.start)
23288                                            ..buffer.anchor_after(range_after_cursor.end),
23289                                    )
23290                                    .collect::<String>()
23291                                    .to_ascii_lowercase();
23292                                completion
23293                                    .label
23294                                    .text
23295                                    .to_ascii_lowercase()
23296                                    .ends_with(&text_after_cursor)
23297                            } else {
23298                                true
23299                            }
23300                        }
23301                    }
23302                }
23303            };
23304
23305            if should_replace {
23306                replace_range.clone()
23307            } else {
23308                insert_range.clone()
23309            }
23310        } else {
23311            replace_range.clone()
23312        }
23313    };
23314
23315    if range_to_replace
23316        .end
23317        .cmp(cursor_position, &buffer_snapshot)
23318        .is_lt()
23319    {
23320        range_to_replace.end = *cursor_position;
23321    }
23322
23323    let replace_range = range_to_replace.to_offset(buffer);
23324    CompletionEdit {
23325        new_text,
23326        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23327        snippet,
23328    }
23329}
23330
23331struct CompletionEdit {
23332    new_text: String,
23333    replace_range: Range<BufferOffset>,
23334    snippet: Option<Snippet>,
23335}
23336
23337fn comment_delimiter_for_newline(
23338    start_point: &Point,
23339    buffer: &MultiBufferSnapshot,
23340    language: &LanguageScope,
23341) -> Option<Arc<str>> {
23342    let delimiters = language.line_comment_prefixes();
23343    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
23344    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23345
23346    let num_of_whitespaces = snapshot
23347        .chars_for_range(range.clone())
23348        .take_while(|c| c.is_whitespace())
23349        .count();
23350    let comment_candidate = snapshot
23351        .chars_for_range(range.clone())
23352        .skip(num_of_whitespaces)
23353        .take(max_len_of_delimiter)
23354        .collect::<String>();
23355    let (delimiter, trimmed_len) = delimiters
23356        .iter()
23357        .filter_map(|delimiter| {
23358            let prefix = delimiter.trim_end();
23359            if comment_candidate.starts_with(prefix) {
23360                Some((delimiter, prefix.len()))
23361            } else {
23362                None
23363            }
23364        })
23365        .max_by_key(|(_, len)| *len)?;
23366
23367    if let Some(BlockCommentConfig {
23368        start: block_start, ..
23369    }) = language.block_comment()
23370    {
23371        let block_start_trimmed = block_start.trim_end();
23372        if block_start_trimmed.starts_with(delimiter.trim_end()) {
23373            let line_content = snapshot
23374                .chars_for_range(range)
23375                .skip(num_of_whitespaces)
23376                .take(block_start_trimmed.len())
23377                .collect::<String>();
23378
23379            if line_content.starts_with(block_start_trimmed) {
23380                return None;
23381            }
23382        }
23383    }
23384
23385    let cursor_is_placed_after_comment_marker =
23386        num_of_whitespaces + trimmed_len <= start_point.column as usize;
23387    if cursor_is_placed_after_comment_marker {
23388        Some(delimiter.clone())
23389    } else {
23390        None
23391    }
23392}
23393
23394fn documentation_delimiter_for_newline(
23395    start_point: &Point,
23396    buffer: &MultiBufferSnapshot,
23397    language: &LanguageScope,
23398    newline_formatting: &mut NewlineFormatting,
23399) -> Option<Arc<str>> {
23400    let BlockCommentConfig {
23401        start: start_tag,
23402        end: end_tag,
23403        prefix: delimiter,
23404        tab_size: len,
23405    } = language.documentation_comment()?;
23406    let is_within_block_comment = buffer
23407        .language_scope_at(*start_point)
23408        .is_some_and(|scope| scope.override_name() == Some("comment"));
23409    if !is_within_block_comment {
23410        return None;
23411    }
23412
23413    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23414
23415    let num_of_whitespaces = snapshot
23416        .chars_for_range(range.clone())
23417        .take_while(|c| c.is_whitespace())
23418        .count();
23419
23420    // 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.
23421    let column = start_point.column;
23422    let cursor_is_after_start_tag = {
23423        let start_tag_len = start_tag.len();
23424        let start_tag_line = snapshot
23425            .chars_for_range(range.clone())
23426            .skip(num_of_whitespaces)
23427            .take(start_tag_len)
23428            .collect::<String>();
23429        if start_tag_line.starts_with(start_tag.as_ref()) {
23430            num_of_whitespaces + start_tag_len <= column as usize
23431        } else {
23432            false
23433        }
23434    };
23435
23436    let cursor_is_after_delimiter = {
23437        let delimiter_trim = delimiter.trim_end();
23438        let delimiter_line = snapshot
23439            .chars_for_range(range.clone())
23440            .skip(num_of_whitespaces)
23441            .take(delimiter_trim.len())
23442            .collect::<String>();
23443        if delimiter_line.starts_with(delimiter_trim) {
23444            num_of_whitespaces + delimiter_trim.len() <= column as usize
23445        } else {
23446            false
23447        }
23448    };
23449
23450    let cursor_is_before_end_tag_if_exists = {
23451        let mut char_position = 0u32;
23452        let mut end_tag_offset = None;
23453
23454        'outer: for chunk in snapshot.text_for_range(range) {
23455            if let Some(byte_pos) = chunk.find(&**end_tag) {
23456                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
23457                end_tag_offset = Some(char_position + chars_before_match);
23458                break 'outer;
23459            }
23460            char_position += chunk.chars().count() as u32;
23461        }
23462
23463        if let Some(end_tag_offset) = end_tag_offset {
23464            let cursor_is_before_end_tag = column <= end_tag_offset;
23465            if cursor_is_after_start_tag {
23466                if cursor_is_before_end_tag {
23467                    newline_formatting.insert_extra_newline = true;
23468                }
23469                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
23470                if cursor_is_at_start_of_end_tag {
23471                    newline_formatting.indent_on_extra_newline.len = *len;
23472                }
23473            }
23474            cursor_is_before_end_tag
23475        } else {
23476            true
23477        }
23478    };
23479
23480    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
23481        && cursor_is_before_end_tag_if_exists
23482    {
23483        if cursor_is_after_start_tag {
23484            newline_formatting.indent_on_newline.len = *len;
23485        }
23486        Some(delimiter.clone())
23487    } else {
23488        None
23489    }
23490}
23491
23492#[derive(Debug, Default)]
23493struct NewlineFormatting {
23494    insert_extra_newline: bool,
23495    indent_on_newline: IndentSize,
23496    indent_on_extra_newline: IndentSize,
23497}
23498
23499impl NewlineFormatting {
23500    fn new(
23501        buffer: &MultiBufferSnapshot,
23502        range: Range<MultiBufferOffset>,
23503        language: &LanguageScope,
23504    ) -> Self {
23505        Self {
23506            insert_extra_newline: Self::insert_extra_newline_brackets(
23507                buffer,
23508                range.clone(),
23509                language,
23510            ) || Self::insert_extra_newline_tree_sitter(buffer, range),
23511            indent_on_newline: IndentSize::spaces(0),
23512            indent_on_extra_newline: IndentSize::spaces(0),
23513        }
23514    }
23515
23516    fn insert_extra_newline_brackets(
23517        buffer: &MultiBufferSnapshot,
23518        range: Range<MultiBufferOffset>,
23519        language: &language::LanguageScope,
23520    ) -> bool {
23521        let leading_whitespace_len = buffer
23522            .reversed_chars_at(range.start)
23523            .take_while(|c| c.is_whitespace() && *c != '\n')
23524            .map(|c| c.len_utf8())
23525            .sum::<usize>();
23526        let trailing_whitespace_len = buffer
23527            .chars_at(range.end)
23528            .take_while(|c| c.is_whitespace() && *c != '\n')
23529            .map(|c| c.len_utf8())
23530            .sum::<usize>();
23531        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23532
23533        language.brackets().any(|(pair, enabled)| {
23534            let pair_start = pair.start.trim_end();
23535            let pair_end = pair.end.trim_start();
23536
23537            enabled
23538                && pair.newline
23539                && buffer.contains_str_at(range.end, pair_end)
23540                && buffer.contains_str_at(
23541                    range.start.saturating_sub_usize(pair_start.len()),
23542                    pair_start,
23543                )
23544        })
23545    }
23546
23547    fn insert_extra_newline_tree_sitter(
23548        buffer: &MultiBufferSnapshot,
23549        range: Range<MultiBufferOffset>,
23550    ) -> bool {
23551        let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23552            [(buffer, range, _)] => (*buffer, range.clone()),
23553            _ => return false,
23554        };
23555        let pair = {
23556            let mut result: Option<BracketMatch<usize>> = None;
23557
23558            for pair in buffer
23559                .all_bracket_ranges(range.start.0..range.end.0)
23560                .filter(move |pair| {
23561                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23562                })
23563            {
23564                let len = pair.close_range.end - pair.open_range.start;
23565
23566                if let Some(existing) = &result {
23567                    let existing_len = existing.close_range.end - existing.open_range.start;
23568                    if len > existing_len {
23569                        continue;
23570                    }
23571                }
23572
23573                result = Some(pair);
23574            }
23575
23576            result
23577        };
23578        let Some(pair) = pair else {
23579            return false;
23580        };
23581        pair.newline_only
23582            && buffer
23583                .chars_for_range(pair.open_range.end..range.start.0)
23584                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23585                .all(|c| c.is_whitespace() && c != '\n')
23586    }
23587}
23588
23589fn update_uncommitted_diff_for_buffer(
23590    editor: Entity<Editor>,
23591    project: &Entity<Project>,
23592    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23593    buffer: Entity<MultiBuffer>,
23594    cx: &mut App,
23595) -> Task<()> {
23596    let mut tasks = Vec::new();
23597    project.update(cx, |project, cx| {
23598        for buffer in buffers {
23599            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23600                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23601            }
23602        }
23603    });
23604    cx.spawn(async move |cx| {
23605        let diffs = future::join_all(tasks).await;
23606        if editor
23607            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23608            .unwrap_or(false)
23609        {
23610            return;
23611        }
23612
23613        buffer
23614            .update(cx, |buffer, cx| {
23615                for diff in diffs.into_iter().flatten() {
23616                    buffer.add_diff(diff, cx);
23617                }
23618            })
23619            .ok();
23620    })
23621}
23622
23623fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23624    let tab_size = tab_size.get() as usize;
23625    let mut width = offset;
23626
23627    for ch in text.chars() {
23628        width += if ch == '\t' {
23629            tab_size - (width % tab_size)
23630        } else {
23631            1
23632        };
23633    }
23634
23635    width - offset
23636}
23637
23638#[cfg(test)]
23639mod tests {
23640    use super::*;
23641
23642    #[test]
23643    fn test_string_size_with_expanded_tabs() {
23644        let nz = |val| NonZeroU32::new(val).unwrap();
23645        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23646        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23647        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23648        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23649        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23650        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23651        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23652        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23653    }
23654}
23655
23656/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23657struct WordBreakingTokenizer<'a> {
23658    input: &'a str,
23659}
23660
23661impl<'a> WordBreakingTokenizer<'a> {
23662    fn new(input: &'a str) -> Self {
23663        Self { input }
23664    }
23665}
23666
23667fn is_char_ideographic(ch: char) -> bool {
23668    use unicode_script::Script::*;
23669    use unicode_script::UnicodeScript;
23670    matches!(ch.script(), Han | Tangut | Yi)
23671}
23672
23673fn is_grapheme_ideographic(text: &str) -> bool {
23674    text.chars().any(is_char_ideographic)
23675}
23676
23677fn is_grapheme_whitespace(text: &str) -> bool {
23678    text.chars().any(|x| x.is_whitespace())
23679}
23680
23681fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23682    text.chars()
23683        .next()
23684        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23685}
23686
23687#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23688enum WordBreakToken<'a> {
23689    Word { token: &'a str, grapheme_len: usize },
23690    InlineWhitespace { token: &'a str, grapheme_len: usize },
23691    Newline,
23692}
23693
23694impl<'a> Iterator for WordBreakingTokenizer<'a> {
23695    /// Yields a span, the count of graphemes in the token, and whether it was
23696    /// whitespace. Note that it also breaks at word boundaries.
23697    type Item = WordBreakToken<'a>;
23698
23699    fn next(&mut self) -> Option<Self::Item> {
23700        use unicode_segmentation::UnicodeSegmentation;
23701        if self.input.is_empty() {
23702            return None;
23703        }
23704
23705        let mut iter = self.input.graphemes(true).peekable();
23706        let mut offset = 0;
23707        let mut grapheme_len = 0;
23708        if let Some(first_grapheme) = iter.next() {
23709            let is_newline = first_grapheme == "\n";
23710            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23711            offset += first_grapheme.len();
23712            grapheme_len += 1;
23713            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23714                if let Some(grapheme) = iter.peek().copied()
23715                    && should_stay_with_preceding_ideograph(grapheme)
23716                {
23717                    offset += grapheme.len();
23718                    grapheme_len += 1;
23719                }
23720            } else {
23721                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23722                let mut next_word_bound = words.peek().copied();
23723                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23724                    next_word_bound = words.next();
23725                }
23726                while let Some(grapheme) = iter.peek().copied() {
23727                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23728                        break;
23729                    };
23730                    if is_grapheme_whitespace(grapheme) != is_whitespace
23731                        || (grapheme == "\n") != is_newline
23732                    {
23733                        break;
23734                    };
23735                    offset += grapheme.len();
23736                    grapheme_len += 1;
23737                    iter.next();
23738                }
23739            }
23740            let token = &self.input[..offset];
23741            self.input = &self.input[offset..];
23742            if token == "\n" {
23743                Some(WordBreakToken::Newline)
23744            } else if is_whitespace {
23745                Some(WordBreakToken::InlineWhitespace {
23746                    token,
23747                    grapheme_len,
23748                })
23749            } else {
23750                Some(WordBreakToken::Word {
23751                    token,
23752                    grapheme_len,
23753                })
23754            }
23755        } else {
23756            None
23757        }
23758    }
23759}
23760
23761#[test]
23762fn test_word_breaking_tokenizer() {
23763    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23764        ("", &[]),
23765        ("  ", &[whitespace("  ", 2)]),
23766        ("Ʒ", &[word("Ʒ", 1)]),
23767        ("Ǽ", &[word("Ǽ", 1)]),
23768        ("", &[word("", 1)]),
23769        ("⋑⋑", &[word("⋑⋑", 2)]),
23770        (
23771            "原理,进而",
23772            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23773        ),
23774        (
23775            "hello world",
23776            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23777        ),
23778        (
23779            "hello, world",
23780            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23781        ),
23782        (
23783            "  hello world",
23784            &[
23785                whitespace("  ", 2),
23786                word("hello", 5),
23787                whitespace(" ", 1),
23788                word("world", 5),
23789            ],
23790        ),
23791        (
23792            "这是什么 \n 钢笔",
23793            &[
23794                word("", 1),
23795                word("", 1),
23796                word("", 1),
23797                word("", 1),
23798                whitespace(" ", 1),
23799                newline(),
23800                whitespace(" ", 1),
23801                word("", 1),
23802                word("", 1),
23803            ],
23804        ),
23805        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23806    ];
23807
23808    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23809        WordBreakToken::Word {
23810            token,
23811            grapheme_len,
23812        }
23813    }
23814
23815    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23816        WordBreakToken::InlineWhitespace {
23817            token,
23818            grapheme_len,
23819        }
23820    }
23821
23822    fn newline() -> WordBreakToken<'static> {
23823        WordBreakToken::Newline
23824    }
23825
23826    for (input, result) in tests {
23827        assert_eq!(
23828            WordBreakingTokenizer::new(input)
23829                .collect::<Vec<_>>()
23830                .as_slice(),
23831            *result,
23832        );
23833    }
23834}
23835
23836fn wrap_with_prefix(
23837    first_line_prefix: String,
23838    subsequent_lines_prefix: String,
23839    unwrapped_text: String,
23840    wrap_column: usize,
23841    tab_size: NonZeroU32,
23842    preserve_existing_whitespace: bool,
23843) -> String {
23844    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23845    let subsequent_lines_prefix_len =
23846        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23847    let mut wrapped_text = String::new();
23848    let mut current_line = first_line_prefix;
23849    let mut is_first_line = true;
23850
23851    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23852    let mut current_line_len = first_line_prefix_len;
23853    let mut in_whitespace = false;
23854    for token in tokenizer {
23855        let have_preceding_whitespace = in_whitespace;
23856        match token {
23857            WordBreakToken::Word {
23858                token,
23859                grapheme_len,
23860            } => {
23861                in_whitespace = false;
23862                let current_prefix_len = if is_first_line {
23863                    first_line_prefix_len
23864                } else {
23865                    subsequent_lines_prefix_len
23866                };
23867                if current_line_len + grapheme_len > wrap_column
23868                    && current_line_len != current_prefix_len
23869                {
23870                    wrapped_text.push_str(current_line.trim_end());
23871                    wrapped_text.push('\n');
23872                    is_first_line = false;
23873                    current_line = subsequent_lines_prefix.clone();
23874                    current_line_len = subsequent_lines_prefix_len;
23875                }
23876                current_line.push_str(token);
23877                current_line_len += grapheme_len;
23878            }
23879            WordBreakToken::InlineWhitespace {
23880                mut token,
23881                mut grapheme_len,
23882            } => {
23883                in_whitespace = true;
23884                if have_preceding_whitespace && !preserve_existing_whitespace {
23885                    continue;
23886                }
23887                if !preserve_existing_whitespace {
23888                    // Keep a single whitespace grapheme as-is
23889                    if let Some(first) =
23890                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23891                    {
23892                        token = first;
23893                    } else {
23894                        token = " ";
23895                    }
23896                    grapheme_len = 1;
23897                }
23898                let current_prefix_len = if is_first_line {
23899                    first_line_prefix_len
23900                } else {
23901                    subsequent_lines_prefix_len
23902                };
23903                if current_line_len + grapheme_len > wrap_column {
23904                    wrapped_text.push_str(current_line.trim_end());
23905                    wrapped_text.push('\n');
23906                    is_first_line = false;
23907                    current_line = subsequent_lines_prefix.clone();
23908                    current_line_len = subsequent_lines_prefix_len;
23909                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23910                    current_line.push_str(token);
23911                    current_line_len += grapheme_len;
23912                }
23913            }
23914            WordBreakToken::Newline => {
23915                in_whitespace = true;
23916                let current_prefix_len = if is_first_line {
23917                    first_line_prefix_len
23918                } else {
23919                    subsequent_lines_prefix_len
23920                };
23921                if preserve_existing_whitespace {
23922                    wrapped_text.push_str(current_line.trim_end());
23923                    wrapped_text.push('\n');
23924                    is_first_line = false;
23925                    current_line = subsequent_lines_prefix.clone();
23926                    current_line_len = subsequent_lines_prefix_len;
23927                } else if have_preceding_whitespace {
23928                    continue;
23929                } else if current_line_len + 1 > wrap_column
23930                    && current_line_len != current_prefix_len
23931                {
23932                    wrapped_text.push_str(current_line.trim_end());
23933                    wrapped_text.push('\n');
23934                    is_first_line = false;
23935                    current_line = subsequent_lines_prefix.clone();
23936                    current_line_len = subsequent_lines_prefix_len;
23937                } else if current_line_len != current_prefix_len {
23938                    current_line.push(' ');
23939                    current_line_len += 1;
23940                }
23941            }
23942        }
23943    }
23944
23945    if !current_line.is_empty() {
23946        wrapped_text.push_str(&current_line);
23947    }
23948    wrapped_text
23949}
23950
23951#[test]
23952fn test_wrap_with_prefix() {
23953    assert_eq!(
23954        wrap_with_prefix(
23955            "# ".to_string(),
23956            "# ".to_string(),
23957            "abcdefg".to_string(),
23958            4,
23959            NonZeroU32::new(4).unwrap(),
23960            false,
23961        ),
23962        "# abcdefg"
23963    );
23964    assert_eq!(
23965        wrap_with_prefix(
23966            "".to_string(),
23967            "".to_string(),
23968            "\thello world".to_string(),
23969            8,
23970            NonZeroU32::new(4).unwrap(),
23971            false,
23972        ),
23973        "hello\nworld"
23974    );
23975    assert_eq!(
23976        wrap_with_prefix(
23977            "// ".to_string(),
23978            "// ".to_string(),
23979            "xx \nyy zz aa bb cc".to_string(),
23980            12,
23981            NonZeroU32::new(4).unwrap(),
23982            false,
23983        ),
23984        "// xx yy zz\n// aa bb cc"
23985    );
23986    assert_eq!(
23987        wrap_with_prefix(
23988            String::new(),
23989            String::new(),
23990            "这是什么 \n 钢笔".to_string(),
23991            3,
23992            NonZeroU32::new(4).unwrap(),
23993            false,
23994        ),
23995        "这是什\n么 钢\n"
23996    );
23997    assert_eq!(
23998        wrap_with_prefix(
23999            String::new(),
24000            String::new(),
24001            format!("foo{}bar", '\u{2009}'), // thin space
24002            80,
24003            NonZeroU32::new(4).unwrap(),
24004            false,
24005        ),
24006        format!("foo{}bar", '\u{2009}')
24007    );
24008}
24009
24010pub trait CollaborationHub {
24011    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
24012    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
24013    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
24014}
24015
24016impl CollaborationHub for Entity<Project> {
24017    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
24018        self.read(cx).collaborators()
24019    }
24020
24021    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
24022        self.read(cx).user_store().read(cx).participant_indices()
24023    }
24024
24025    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
24026        let this = self.read(cx);
24027        let user_ids = this.collaborators().values().map(|c| c.user_id);
24028        this.user_store().read(cx).participant_names(user_ids, cx)
24029    }
24030}
24031
24032pub trait SemanticsProvider {
24033    fn hover(
24034        &self,
24035        buffer: &Entity<Buffer>,
24036        position: text::Anchor,
24037        cx: &mut App,
24038    ) -> Option<Task<Option<Vec<project::Hover>>>>;
24039
24040    fn inline_values(
24041        &self,
24042        buffer_handle: Entity<Buffer>,
24043        range: Range<text::Anchor>,
24044        cx: &mut App,
24045    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
24046
24047    fn applicable_inlay_chunks(
24048        &self,
24049        buffer: &Entity<Buffer>,
24050        ranges: &[Range<text::Anchor>],
24051        cx: &mut App,
24052    ) -> Vec<Range<BufferRow>>;
24053
24054    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
24055
24056    fn inlay_hints(
24057        &self,
24058        invalidate: InvalidationStrategy,
24059        buffer: Entity<Buffer>,
24060        ranges: Vec<Range<text::Anchor>>,
24061        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24062        cx: &mut App,
24063    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
24064
24065    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
24066
24067    fn document_highlights(
24068        &self,
24069        buffer: &Entity<Buffer>,
24070        position: text::Anchor,
24071        cx: &mut App,
24072    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
24073
24074    fn definitions(
24075        &self,
24076        buffer: &Entity<Buffer>,
24077        position: text::Anchor,
24078        kind: GotoDefinitionKind,
24079        cx: &mut App,
24080    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
24081
24082    fn range_for_rename(
24083        &self,
24084        buffer: &Entity<Buffer>,
24085        position: text::Anchor,
24086        cx: &mut App,
24087    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
24088
24089    fn perform_rename(
24090        &self,
24091        buffer: &Entity<Buffer>,
24092        position: text::Anchor,
24093        new_name: String,
24094        cx: &mut App,
24095    ) -> Option<Task<Result<ProjectTransaction>>>;
24096}
24097
24098pub trait CompletionProvider {
24099    fn completions(
24100        &self,
24101        excerpt_id: ExcerptId,
24102        buffer: &Entity<Buffer>,
24103        buffer_position: text::Anchor,
24104        trigger: CompletionContext,
24105        window: &mut Window,
24106        cx: &mut Context<Editor>,
24107    ) -> Task<Result<Vec<CompletionResponse>>>;
24108
24109    fn resolve_completions(
24110        &self,
24111        _buffer: Entity<Buffer>,
24112        _completion_indices: Vec<usize>,
24113        _completions: Rc<RefCell<Box<[Completion]>>>,
24114        _cx: &mut Context<Editor>,
24115    ) -> Task<Result<bool>> {
24116        Task::ready(Ok(false))
24117    }
24118
24119    fn apply_additional_edits_for_completion(
24120        &self,
24121        _buffer: Entity<Buffer>,
24122        _completions: Rc<RefCell<Box<[Completion]>>>,
24123        _completion_index: usize,
24124        _push_to_history: bool,
24125        _cx: &mut Context<Editor>,
24126    ) -> Task<Result<Option<language::Transaction>>> {
24127        Task::ready(Ok(None))
24128    }
24129
24130    fn is_completion_trigger(
24131        &self,
24132        buffer: &Entity<Buffer>,
24133        position: language::Anchor,
24134        text: &str,
24135        trigger_in_words: bool,
24136        cx: &mut Context<Editor>,
24137    ) -> bool;
24138
24139    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24140
24141    fn sort_completions(&self) -> bool {
24142        true
24143    }
24144
24145    fn filter_completions(&self) -> bool {
24146        true
24147    }
24148
24149    fn show_snippets(&self) -> bool {
24150        false
24151    }
24152}
24153
24154pub trait CodeActionProvider {
24155    fn id(&self) -> Arc<str>;
24156
24157    fn code_actions(
24158        &self,
24159        buffer: &Entity<Buffer>,
24160        range: Range<text::Anchor>,
24161        window: &mut Window,
24162        cx: &mut App,
24163    ) -> Task<Result<Vec<CodeAction>>>;
24164
24165    fn apply_code_action(
24166        &self,
24167        buffer_handle: Entity<Buffer>,
24168        action: CodeAction,
24169        excerpt_id: ExcerptId,
24170        push_to_history: bool,
24171        window: &mut Window,
24172        cx: &mut App,
24173    ) -> Task<Result<ProjectTransaction>>;
24174}
24175
24176impl CodeActionProvider for Entity<Project> {
24177    fn id(&self) -> Arc<str> {
24178        "project".into()
24179    }
24180
24181    fn code_actions(
24182        &self,
24183        buffer: &Entity<Buffer>,
24184        range: Range<text::Anchor>,
24185        _window: &mut Window,
24186        cx: &mut App,
24187    ) -> Task<Result<Vec<CodeAction>>> {
24188        self.update(cx, |project, cx| {
24189            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24190            let code_actions = project.code_actions(buffer, range, None, cx);
24191            cx.background_spawn(async move {
24192                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24193                Ok(code_lens_actions
24194                    .context("code lens fetch")?
24195                    .into_iter()
24196                    .flatten()
24197                    .chain(
24198                        code_actions
24199                            .context("code action fetch")?
24200                            .into_iter()
24201                            .flatten(),
24202                    )
24203                    .collect())
24204            })
24205        })
24206    }
24207
24208    fn apply_code_action(
24209        &self,
24210        buffer_handle: Entity<Buffer>,
24211        action: CodeAction,
24212        _excerpt_id: ExcerptId,
24213        push_to_history: bool,
24214        _window: &mut Window,
24215        cx: &mut App,
24216    ) -> Task<Result<ProjectTransaction>> {
24217        self.update(cx, |project, cx| {
24218            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24219        })
24220    }
24221}
24222
24223fn snippet_completions(
24224    project: &Project,
24225    buffer: &Entity<Buffer>,
24226    buffer_anchor: text::Anchor,
24227    classifier: CharClassifier,
24228    cx: &mut App,
24229) -> Task<Result<CompletionResponse>> {
24230    let languages = buffer.read(cx).languages_at(buffer_anchor);
24231    let snippet_store = project.snippets().read(cx);
24232
24233    let scopes: Vec<_> = languages
24234        .iter()
24235        .filter_map(|language| {
24236            let language_name = language.lsp_id();
24237            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24238
24239            if snippets.is_empty() {
24240                None
24241            } else {
24242                Some((language.default_scope(), snippets))
24243            }
24244        })
24245        .collect();
24246
24247    if scopes.is_empty() {
24248        return Task::ready(Ok(CompletionResponse {
24249            completions: vec![],
24250            display_options: CompletionDisplayOptions::default(),
24251            is_incomplete: false,
24252        }));
24253    }
24254
24255    let snapshot = buffer.read(cx).text_snapshot();
24256    let executor = cx.background_executor().clone();
24257
24258    cx.background_spawn(async move {
24259        let is_word_char = |c| classifier.is_word(c);
24260
24261        let mut is_incomplete = false;
24262        let mut completions: Vec<Completion> = Vec::new();
24263
24264        const MAX_PREFIX_LEN: usize = 128;
24265        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24266        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24267        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24268
24269        let max_buffer_window: String = snapshot
24270            .text_for_range(window_start..buffer_offset)
24271            .collect();
24272
24273        if max_buffer_window.is_empty() {
24274            return Ok(CompletionResponse {
24275                completions: vec![],
24276                display_options: CompletionDisplayOptions::default(),
24277                is_incomplete: true,
24278            });
24279        }
24280
24281        for (_scope, snippets) in scopes.into_iter() {
24282            // Sort snippets by word count to match longer snippet prefixes first.
24283            let mut sorted_snippet_candidates = snippets
24284                .iter()
24285                .enumerate()
24286                .flat_map(|(snippet_ix, snippet)| {
24287                    snippet
24288                        .prefix
24289                        .iter()
24290                        .enumerate()
24291                        .map(move |(prefix_ix, prefix)| {
24292                            let word_count =
24293                                snippet_candidate_suffixes(prefix, is_word_char).count();
24294                            ((snippet_ix, prefix_ix), prefix, word_count)
24295                        })
24296                })
24297                .collect_vec();
24298            sorted_snippet_candidates
24299                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24300
24301            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24302
24303            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24304                .take(
24305                    sorted_snippet_candidates
24306                        .first()
24307                        .map(|(_, _, word_count)| *word_count)
24308                        .unwrap_or_default(),
24309                )
24310                .collect_vec();
24311
24312            const MAX_RESULTS: usize = 100;
24313            // Each match also remembers how many characters from the buffer it consumed
24314            let mut matches: Vec<(StringMatch, usize)> = vec![];
24315
24316            let mut snippet_list_cutoff_index = 0;
24317            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24318                let word_count = buffer_index + 1;
24319                // Increase `snippet_list_cutoff_index` until we have all of the
24320                // snippets with sufficiently many words.
24321                while sorted_snippet_candidates
24322                    .get(snippet_list_cutoff_index)
24323                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24324                        *snippet_word_count >= word_count
24325                    })
24326                {
24327                    snippet_list_cutoff_index += 1;
24328                }
24329
24330                // Take only the candidates with at least `word_count` many words
24331                let snippet_candidates_at_word_len =
24332                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24333
24334                let candidates = snippet_candidates_at_word_len
24335                    .iter()
24336                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24337                    .enumerate() // index in `sorted_snippet_candidates`
24338                    // First char must match
24339                    .filter(|(_ix, prefix)| {
24340                        itertools::equal(
24341                            prefix
24342                                .chars()
24343                                .next()
24344                                .into_iter()
24345                                .flat_map(|c| c.to_lowercase()),
24346                            buffer_window
24347                                .chars()
24348                                .next()
24349                                .into_iter()
24350                                .flat_map(|c| c.to_lowercase()),
24351                        )
24352                    })
24353                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24354                    .collect::<Vec<StringMatchCandidate>>();
24355
24356                matches.extend(
24357                    fuzzy::match_strings(
24358                        &candidates,
24359                        &buffer_window,
24360                        buffer_window.chars().any(|c| c.is_uppercase()),
24361                        true,
24362                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24363                        &Default::default(),
24364                        executor.clone(),
24365                    )
24366                    .await
24367                    .into_iter()
24368                    .map(|string_match| (string_match, buffer_window.len())),
24369                );
24370
24371                if matches.len() >= MAX_RESULTS {
24372                    break;
24373                }
24374            }
24375
24376            let to_lsp = |point: &text::Anchor| {
24377                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24378                point_to_lsp(end)
24379            };
24380            let lsp_end = to_lsp(&buffer_anchor);
24381
24382            if matches.len() >= MAX_RESULTS {
24383                is_incomplete = true;
24384            }
24385
24386            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24387                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24388                    sorted_snippet_candidates[string_match.candidate_id];
24389                let snippet = &snippets[snippet_index];
24390                let start = buffer_offset - buffer_window_len;
24391                let start = snapshot.anchor_before(start);
24392                let range = start..buffer_anchor;
24393                let lsp_start = to_lsp(&start);
24394                let lsp_range = lsp::Range {
24395                    start: lsp_start,
24396                    end: lsp_end,
24397                };
24398                Completion {
24399                    replace_range: range,
24400                    new_text: snippet.body.clone(),
24401                    source: CompletionSource::Lsp {
24402                        insert_range: None,
24403                        server_id: LanguageServerId(usize::MAX),
24404                        resolved: true,
24405                        lsp_completion: Box::new(lsp::CompletionItem {
24406                            label: snippet.prefix.first().unwrap().clone(),
24407                            kind: Some(CompletionItemKind::SNIPPET),
24408                            label_details: snippet.description.as_ref().map(|description| {
24409                                lsp::CompletionItemLabelDetails {
24410                                    detail: Some(description.clone()),
24411                                    description: None,
24412                                }
24413                            }),
24414                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24415                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24416                                lsp::InsertReplaceEdit {
24417                                    new_text: snippet.body.clone(),
24418                                    insert: lsp_range,
24419                                    replace: lsp_range,
24420                                },
24421                            )),
24422                            filter_text: Some(snippet.body.clone()),
24423                            sort_text: Some(char::MAX.to_string()),
24424                            ..lsp::CompletionItem::default()
24425                        }),
24426                        lsp_defaults: None,
24427                    },
24428                    label: CodeLabel {
24429                        text: matching_prefix.clone(),
24430                        runs: Vec::new(),
24431                        filter_range: 0..matching_prefix.len(),
24432                    },
24433                    icon_path: None,
24434                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24435                        single_line: snippet.name.clone().into(),
24436                        plain_text: snippet
24437                            .description
24438                            .clone()
24439                            .map(|description| description.into()),
24440                    }),
24441                    insert_text_mode: None,
24442                    confirm: None,
24443                    match_start: Some(start),
24444                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24445                }
24446            }));
24447        }
24448
24449        Ok(CompletionResponse {
24450            completions,
24451            display_options: CompletionDisplayOptions::default(),
24452            is_incomplete,
24453        })
24454    })
24455}
24456
24457impl CompletionProvider for Entity<Project> {
24458    fn completions(
24459        &self,
24460        _excerpt_id: ExcerptId,
24461        buffer: &Entity<Buffer>,
24462        buffer_position: text::Anchor,
24463        options: CompletionContext,
24464        _window: &mut Window,
24465        cx: &mut Context<Editor>,
24466    ) -> Task<Result<Vec<CompletionResponse>>> {
24467        self.update(cx, |project, cx| {
24468            let task = project.completions(buffer, buffer_position, options, cx);
24469            cx.background_spawn(task)
24470        })
24471    }
24472
24473    fn resolve_completions(
24474        &self,
24475        buffer: Entity<Buffer>,
24476        completion_indices: Vec<usize>,
24477        completions: Rc<RefCell<Box<[Completion]>>>,
24478        cx: &mut Context<Editor>,
24479    ) -> Task<Result<bool>> {
24480        self.update(cx, |project, cx| {
24481            project.lsp_store().update(cx, |lsp_store, cx| {
24482                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24483            })
24484        })
24485    }
24486
24487    fn apply_additional_edits_for_completion(
24488        &self,
24489        buffer: Entity<Buffer>,
24490        completions: Rc<RefCell<Box<[Completion]>>>,
24491        completion_index: usize,
24492        push_to_history: bool,
24493        cx: &mut Context<Editor>,
24494    ) -> Task<Result<Option<language::Transaction>>> {
24495        self.update(cx, |project, cx| {
24496            project.lsp_store().update(cx, |lsp_store, cx| {
24497                lsp_store.apply_additional_edits_for_completion(
24498                    buffer,
24499                    completions,
24500                    completion_index,
24501                    push_to_history,
24502                    cx,
24503                )
24504            })
24505        })
24506    }
24507
24508    fn is_completion_trigger(
24509        &self,
24510        buffer: &Entity<Buffer>,
24511        position: language::Anchor,
24512        text: &str,
24513        trigger_in_words: bool,
24514        cx: &mut Context<Editor>,
24515    ) -> bool {
24516        let mut chars = text.chars();
24517        let char = if let Some(char) = chars.next() {
24518            char
24519        } else {
24520            return false;
24521        };
24522        if chars.next().is_some() {
24523            return false;
24524        }
24525
24526        let buffer = buffer.read(cx);
24527        let snapshot = buffer.snapshot();
24528        let classifier = snapshot
24529            .char_classifier_at(position)
24530            .scope_context(Some(CharScopeContext::Completion));
24531        if trigger_in_words && classifier.is_word(char) {
24532            return true;
24533        }
24534
24535        buffer.completion_triggers().contains(text)
24536    }
24537
24538    fn show_snippets(&self) -> bool {
24539        true
24540    }
24541}
24542
24543impl SemanticsProvider for Entity<Project> {
24544    fn hover(
24545        &self,
24546        buffer: &Entity<Buffer>,
24547        position: text::Anchor,
24548        cx: &mut App,
24549    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24550        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24551    }
24552
24553    fn document_highlights(
24554        &self,
24555        buffer: &Entity<Buffer>,
24556        position: text::Anchor,
24557        cx: &mut App,
24558    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24559        Some(self.update(cx, |project, cx| {
24560            project.document_highlights(buffer, position, cx)
24561        }))
24562    }
24563
24564    fn definitions(
24565        &self,
24566        buffer: &Entity<Buffer>,
24567        position: text::Anchor,
24568        kind: GotoDefinitionKind,
24569        cx: &mut App,
24570    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24571        Some(self.update(cx, |project, cx| match kind {
24572            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24573            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24574            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24575            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24576        }))
24577    }
24578
24579    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24580        self.update(cx, |project, cx| {
24581            if project
24582                .active_debug_session(cx)
24583                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24584            {
24585                return true;
24586            }
24587
24588            buffer.update(cx, |buffer, cx| {
24589                project.any_language_server_supports_inlay_hints(buffer, cx)
24590            })
24591        })
24592    }
24593
24594    fn inline_values(
24595        &self,
24596        buffer_handle: Entity<Buffer>,
24597        range: Range<text::Anchor>,
24598        cx: &mut App,
24599    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24600        self.update(cx, |project, cx| {
24601            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24602
24603            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24604        })
24605    }
24606
24607    fn applicable_inlay_chunks(
24608        &self,
24609        buffer: &Entity<Buffer>,
24610        ranges: &[Range<text::Anchor>],
24611        cx: &mut App,
24612    ) -> Vec<Range<BufferRow>> {
24613        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24614            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24615        })
24616    }
24617
24618    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24619        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24620            lsp_store.invalidate_inlay_hints(for_buffers)
24621        });
24622    }
24623
24624    fn inlay_hints(
24625        &self,
24626        invalidate: InvalidationStrategy,
24627        buffer: Entity<Buffer>,
24628        ranges: Vec<Range<text::Anchor>>,
24629        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24630        cx: &mut App,
24631    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24632        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24633            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24634        }))
24635    }
24636
24637    fn range_for_rename(
24638        &self,
24639        buffer: &Entity<Buffer>,
24640        position: text::Anchor,
24641        cx: &mut App,
24642    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24643        Some(self.update(cx, |project, cx| {
24644            let buffer = buffer.clone();
24645            let task = project.prepare_rename(buffer.clone(), position, cx);
24646            cx.spawn(async move |_, cx| {
24647                Ok(match task.await? {
24648                    PrepareRenameResponse::Success(range) => Some(range),
24649                    PrepareRenameResponse::InvalidPosition => None,
24650                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24651                        // Fallback on using TreeSitter info to determine identifier range
24652                        buffer.read_with(cx, |buffer, _| {
24653                            let snapshot = buffer.snapshot();
24654                            let (range, kind) = snapshot.surrounding_word(position, None);
24655                            if kind != Some(CharKind::Word) {
24656                                return None;
24657                            }
24658                            Some(
24659                                snapshot.anchor_before(range.start)
24660                                    ..snapshot.anchor_after(range.end),
24661                            )
24662                        })?
24663                    }
24664                })
24665            })
24666        }))
24667    }
24668
24669    fn perform_rename(
24670        &self,
24671        buffer: &Entity<Buffer>,
24672        position: text::Anchor,
24673        new_name: String,
24674        cx: &mut App,
24675    ) -> Option<Task<Result<ProjectTransaction>>> {
24676        Some(self.update(cx, |project, cx| {
24677            project.perform_rename(buffer.clone(), position, new_name, cx)
24678        }))
24679    }
24680}
24681
24682fn consume_contiguous_rows(
24683    contiguous_row_selections: &mut Vec<Selection<Point>>,
24684    selection: &Selection<Point>,
24685    display_map: &DisplaySnapshot,
24686    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24687) -> (MultiBufferRow, MultiBufferRow) {
24688    contiguous_row_selections.push(selection.clone());
24689    let start_row = starting_row(selection, display_map);
24690    let mut end_row = ending_row(selection, display_map);
24691
24692    while let Some(next_selection) = selections.peek() {
24693        if next_selection.start.row <= end_row.0 {
24694            end_row = ending_row(next_selection, display_map);
24695            contiguous_row_selections.push(selections.next().unwrap().clone());
24696        } else {
24697            break;
24698        }
24699    }
24700    (start_row, end_row)
24701}
24702
24703fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24704    if selection.start.column > 0 {
24705        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24706    } else {
24707        MultiBufferRow(selection.start.row)
24708    }
24709}
24710
24711fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24712    if next_selection.end.column > 0 || next_selection.is_empty() {
24713        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24714    } else {
24715        MultiBufferRow(next_selection.end.row)
24716    }
24717}
24718
24719impl EditorSnapshot {
24720    pub fn remote_selections_in_range<'a>(
24721        &'a self,
24722        range: &'a Range<Anchor>,
24723        collaboration_hub: &dyn CollaborationHub,
24724        cx: &'a App,
24725    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24726        let participant_names = collaboration_hub.user_names(cx);
24727        let participant_indices = collaboration_hub.user_participant_indices(cx);
24728        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24729        let collaborators_by_replica_id = collaborators_by_peer_id
24730            .values()
24731            .map(|collaborator| (collaborator.replica_id, collaborator))
24732            .collect::<HashMap<_, _>>();
24733        self.buffer_snapshot()
24734            .selections_in_range(range, false)
24735            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24736                if replica_id == ReplicaId::AGENT {
24737                    Some(RemoteSelection {
24738                        replica_id,
24739                        selection,
24740                        cursor_shape,
24741                        line_mode,
24742                        collaborator_id: CollaboratorId::Agent,
24743                        user_name: Some("Agent".into()),
24744                        color: cx.theme().players().agent(),
24745                    })
24746                } else {
24747                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24748                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24749                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24750                    Some(RemoteSelection {
24751                        replica_id,
24752                        selection,
24753                        cursor_shape,
24754                        line_mode,
24755                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24756                        user_name,
24757                        color: if let Some(index) = participant_index {
24758                            cx.theme().players().color_for_participant(index.0)
24759                        } else {
24760                            cx.theme().players().absent()
24761                        },
24762                    })
24763                }
24764            })
24765    }
24766
24767    pub fn hunks_for_ranges(
24768        &self,
24769        ranges: impl IntoIterator<Item = Range<Point>>,
24770    ) -> Vec<MultiBufferDiffHunk> {
24771        let mut hunks = Vec::new();
24772        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24773            HashMap::default();
24774        for query_range in ranges {
24775            let query_rows =
24776                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24777            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24778                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24779            ) {
24780                // Include deleted hunks that are adjacent to the query range, because
24781                // otherwise they would be missed.
24782                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24783                if hunk.status().is_deleted() {
24784                    intersects_range |= hunk.row_range.start == query_rows.end;
24785                    intersects_range |= hunk.row_range.end == query_rows.start;
24786                }
24787                if intersects_range {
24788                    if !processed_buffer_rows
24789                        .entry(hunk.buffer_id)
24790                        .or_default()
24791                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24792                    {
24793                        continue;
24794                    }
24795                    hunks.push(hunk);
24796                }
24797            }
24798        }
24799
24800        hunks
24801    }
24802
24803    fn display_diff_hunks_for_rows<'a>(
24804        &'a self,
24805        display_rows: Range<DisplayRow>,
24806        folded_buffers: &'a HashSet<BufferId>,
24807    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24808        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24809        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24810
24811        self.buffer_snapshot()
24812            .diff_hunks_in_range(buffer_start..buffer_end)
24813            .filter_map(|hunk| {
24814                if folded_buffers.contains(&hunk.buffer_id) {
24815                    return None;
24816                }
24817
24818                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24819                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24820
24821                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24822                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24823
24824                let display_hunk = if hunk_display_start.column() != 0 {
24825                    DisplayDiffHunk::Folded {
24826                        display_row: hunk_display_start.row(),
24827                    }
24828                } else {
24829                    let mut end_row = hunk_display_end.row();
24830                    if hunk_display_end.column() > 0 {
24831                        end_row.0 += 1;
24832                    }
24833                    let is_created_file = hunk.is_created_file();
24834
24835                    DisplayDiffHunk::Unfolded {
24836                        status: hunk.status(),
24837                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24838                            ..hunk.diff_base_byte_range.end.0,
24839                        word_diffs: hunk.word_diffs,
24840                        display_row_range: hunk_display_start.row()..end_row,
24841                        multi_buffer_range: Anchor::range_in_buffer(
24842                            hunk.excerpt_id,
24843                            hunk.buffer_range,
24844                        ),
24845                        is_created_file,
24846                    }
24847                };
24848
24849                Some(display_hunk)
24850            })
24851    }
24852
24853    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24854        self.display_snapshot
24855            .buffer_snapshot()
24856            .language_at(position)
24857    }
24858
24859    pub fn is_focused(&self) -> bool {
24860        self.is_focused
24861    }
24862
24863    pub fn placeholder_text(&self) -> Option<String> {
24864        self.placeholder_display_snapshot
24865            .as_ref()
24866            .map(|display_map| display_map.text())
24867    }
24868
24869    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24870        self.scroll_anchor.scroll_position(&self.display_snapshot)
24871    }
24872
24873    pub fn gutter_dimensions(
24874        &self,
24875        font_id: FontId,
24876        font_size: Pixels,
24877        style: &EditorStyle,
24878        window: &mut Window,
24879        cx: &App,
24880    ) -> GutterDimensions {
24881        if self.show_gutter
24882            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
24883            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
24884        {
24885            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24886                matches!(
24887                    ProjectSettings::get_global(cx).git.git_gutter,
24888                    GitGutterSetting::TrackedFiles
24889                )
24890            });
24891            let gutter_settings = EditorSettings::get_global(cx).gutter;
24892            let show_line_numbers = self
24893                .show_line_numbers
24894                .unwrap_or(gutter_settings.line_numbers);
24895            let line_gutter_width = if show_line_numbers {
24896                // Avoid flicker-like gutter resizes when the line number gains another digit by
24897                // only resizing the gutter on files with > 10**min_line_number_digits lines.
24898                let min_width_for_number_on_gutter =
24899                    ch_advance * gutter_settings.min_line_number_digits as f32;
24900                self.max_line_number_width(style, window)
24901                    .max(min_width_for_number_on_gutter)
24902            } else {
24903                0.0.into()
24904            };
24905
24906            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24907            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24908
24909            let git_blame_entries_width =
24910                self.git_blame_gutter_max_author_length
24911                    .map(|max_author_length| {
24912                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24913                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24914
24915                        /// The number of characters to dedicate to gaps and margins.
24916                        const SPACING_WIDTH: usize = 4;
24917
24918                        let max_char_count = max_author_length.min(renderer.max_author_length())
24919                            + ::git::SHORT_SHA_LENGTH
24920                            + MAX_RELATIVE_TIMESTAMP.len()
24921                            + SPACING_WIDTH;
24922
24923                        ch_advance * max_char_count
24924                    });
24925
24926            let is_singleton = self.buffer_snapshot().is_singleton();
24927
24928            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24929            left_padding += if !is_singleton {
24930                ch_width * 4.0
24931            } else if show_runnables || show_breakpoints {
24932                ch_width * 3.0
24933            } else if show_git_gutter && show_line_numbers {
24934                ch_width * 2.0
24935            } else if show_git_gutter || show_line_numbers {
24936                ch_width
24937            } else {
24938                px(0.)
24939            };
24940
24941            let shows_folds = is_singleton && gutter_settings.folds;
24942
24943            let right_padding = if shows_folds && show_line_numbers {
24944                ch_width * 4.0
24945            } else if shows_folds || (!is_singleton && show_line_numbers) {
24946                ch_width * 3.0
24947            } else if show_line_numbers {
24948                ch_width
24949            } else {
24950                px(0.)
24951            };
24952
24953            GutterDimensions {
24954                left_padding,
24955                right_padding,
24956                width: line_gutter_width + left_padding + right_padding,
24957                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24958                git_blame_entries_width,
24959            }
24960        } else if self.offset_content {
24961            GutterDimensions::default_with_margin(font_id, font_size, cx)
24962        } else {
24963            GutterDimensions::default()
24964        }
24965    }
24966
24967    pub fn render_crease_toggle(
24968        &self,
24969        buffer_row: MultiBufferRow,
24970        row_contains_cursor: bool,
24971        editor: Entity<Editor>,
24972        window: &mut Window,
24973        cx: &mut App,
24974    ) -> Option<AnyElement> {
24975        let folded = self.is_line_folded(buffer_row);
24976        let mut is_foldable = false;
24977
24978        if let Some(crease) = self
24979            .crease_snapshot
24980            .query_row(buffer_row, self.buffer_snapshot())
24981        {
24982            is_foldable = true;
24983            match crease {
24984                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24985                    if let Some(render_toggle) = render_toggle {
24986                        let toggle_callback =
24987                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24988                                if folded {
24989                                    editor.update(cx, |editor, cx| {
24990                                        editor.fold_at(buffer_row, window, cx)
24991                                    });
24992                                } else {
24993                                    editor.update(cx, |editor, cx| {
24994                                        editor.unfold_at(buffer_row, window, cx)
24995                                    });
24996                                }
24997                            });
24998                        return Some((render_toggle)(
24999                            buffer_row,
25000                            folded,
25001                            toggle_callback,
25002                            window,
25003                            cx,
25004                        ));
25005                    }
25006                }
25007            }
25008        }
25009
25010        is_foldable |= self.starts_indent(buffer_row);
25011
25012        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
25013            Some(
25014                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
25015                    .toggle_state(folded)
25016                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
25017                        if folded {
25018                            this.unfold_at(buffer_row, window, cx);
25019                        } else {
25020                            this.fold_at(buffer_row, window, cx);
25021                        }
25022                    }))
25023                    .into_any_element(),
25024            )
25025        } else {
25026            None
25027        }
25028    }
25029
25030    pub fn render_crease_trailer(
25031        &self,
25032        buffer_row: MultiBufferRow,
25033        window: &mut Window,
25034        cx: &mut App,
25035    ) -> Option<AnyElement> {
25036        let folded = self.is_line_folded(buffer_row);
25037        if let Crease::Inline { render_trailer, .. } = self
25038            .crease_snapshot
25039            .query_row(buffer_row, self.buffer_snapshot())?
25040        {
25041            let render_trailer = render_trailer.as_ref()?;
25042            Some(render_trailer(buffer_row, folded, window, cx))
25043        } else {
25044            None
25045        }
25046    }
25047
25048    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
25049        let digit_count = self.widest_line_number().ilog10() + 1;
25050        column_pixels(style, digit_count as usize, window)
25051    }
25052}
25053
25054pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
25055    let font_size = style.text.font_size.to_pixels(window.rem_size());
25056    let layout = window.text_system().shape_line(
25057        SharedString::from(" ".repeat(column)),
25058        font_size,
25059        &[TextRun {
25060            len: column,
25061            font: style.text.font(),
25062            color: Hsla::default(),
25063            ..Default::default()
25064        }],
25065        None,
25066    );
25067
25068    layout.width
25069}
25070
25071impl Deref for EditorSnapshot {
25072    type Target = DisplaySnapshot;
25073
25074    fn deref(&self) -> &Self::Target {
25075        &self.display_snapshot
25076    }
25077}
25078
25079#[derive(Clone, Debug, PartialEq, Eq)]
25080pub enum EditorEvent {
25081    InputIgnored {
25082        text: Arc<str>,
25083    },
25084    InputHandled {
25085        utf16_range_to_replace: Option<Range<isize>>,
25086        text: Arc<str>,
25087    },
25088    ExcerptsAdded {
25089        buffer: Entity<Buffer>,
25090        predecessor: ExcerptId,
25091        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
25092    },
25093    ExcerptsRemoved {
25094        ids: Vec<ExcerptId>,
25095        removed_buffer_ids: Vec<BufferId>,
25096    },
25097    BufferFoldToggled {
25098        ids: Vec<ExcerptId>,
25099        folded: bool,
25100    },
25101    ExcerptsEdited {
25102        ids: Vec<ExcerptId>,
25103    },
25104    ExcerptsExpanded {
25105        ids: Vec<ExcerptId>,
25106    },
25107    BufferEdited,
25108    Edited {
25109        transaction_id: clock::Lamport,
25110    },
25111    Reparsed(BufferId),
25112    Focused,
25113    FocusedIn,
25114    Blurred,
25115    DirtyChanged,
25116    Saved,
25117    TitleChanged,
25118    SelectionsChanged {
25119        local: bool,
25120    },
25121    ScrollPositionChanged {
25122        local: bool,
25123        autoscroll: bool,
25124    },
25125    TransactionUndone {
25126        transaction_id: clock::Lamport,
25127    },
25128    TransactionBegun {
25129        transaction_id: clock::Lamport,
25130    },
25131    CursorShapeChanged,
25132    BreadcrumbsChanged,
25133    PushedToNavHistory {
25134        anchor: Anchor,
25135        is_deactivate: bool,
25136    },
25137}
25138
25139impl EventEmitter<EditorEvent> for Editor {}
25140
25141impl Focusable for Editor {
25142    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25143        self.focus_handle.clone()
25144    }
25145}
25146
25147impl Render for Editor {
25148    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25149        EditorElement::new(&cx.entity(), self.create_style(cx))
25150    }
25151}
25152
25153impl EntityInputHandler for Editor {
25154    fn text_for_range(
25155        &mut self,
25156        range_utf16: Range<usize>,
25157        adjusted_range: &mut Option<Range<usize>>,
25158        _: &mut Window,
25159        cx: &mut Context<Self>,
25160    ) -> Option<String> {
25161        let snapshot = self.buffer.read(cx).read(cx);
25162        let start = snapshot.clip_offset_utf16(
25163            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25164            Bias::Left,
25165        );
25166        let end = snapshot.clip_offset_utf16(
25167            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25168            Bias::Right,
25169        );
25170        if (start.0.0..end.0.0) != range_utf16 {
25171            adjusted_range.replace(start.0.0..end.0.0);
25172        }
25173        Some(snapshot.text_for_range(start..end).collect())
25174    }
25175
25176    fn selected_text_range(
25177        &mut self,
25178        ignore_disabled_input: bool,
25179        _: &mut Window,
25180        cx: &mut Context<Self>,
25181    ) -> Option<UTF16Selection> {
25182        // Prevent the IME menu from appearing when holding down an alphabetic key
25183        // while input is disabled.
25184        if !ignore_disabled_input && !self.input_enabled {
25185            return None;
25186        }
25187
25188        let selection = self
25189            .selections
25190            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25191        let range = selection.range();
25192
25193        Some(UTF16Selection {
25194            range: range.start.0.0..range.end.0.0,
25195            reversed: selection.reversed,
25196        })
25197    }
25198
25199    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25200        let snapshot = self.buffer.read(cx).read(cx);
25201        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25202        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25203    }
25204
25205    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25206        self.clear_highlights::<InputComposition>(cx);
25207        self.ime_transaction.take();
25208    }
25209
25210    fn replace_text_in_range(
25211        &mut self,
25212        range_utf16: Option<Range<usize>>,
25213        text: &str,
25214        window: &mut Window,
25215        cx: &mut Context<Self>,
25216    ) {
25217        if !self.input_enabled {
25218            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25219            return;
25220        }
25221
25222        self.transact(window, cx, |this, window, cx| {
25223            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25224                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25225                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25226                Some(this.selection_replacement_ranges(range_utf16, cx))
25227            } else {
25228                this.marked_text_ranges(cx)
25229            };
25230
25231            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25232                let newest_selection_id = this.selections.newest_anchor().id;
25233                this.selections
25234                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25235                    .iter()
25236                    .zip(ranges_to_replace.iter())
25237                    .find_map(|(selection, range)| {
25238                        if selection.id == newest_selection_id {
25239                            Some(
25240                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25241                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25242                            )
25243                        } else {
25244                            None
25245                        }
25246                    })
25247            });
25248
25249            cx.emit(EditorEvent::InputHandled {
25250                utf16_range_to_replace: range_to_replace,
25251                text: text.into(),
25252            });
25253
25254            if let Some(new_selected_ranges) = new_selected_ranges {
25255                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25256                    selections.select_ranges(new_selected_ranges)
25257                });
25258                this.backspace(&Default::default(), window, cx);
25259            }
25260
25261            this.handle_input(text, window, cx);
25262        });
25263
25264        if let Some(transaction) = self.ime_transaction {
25265            self.buffer.update(cx, |buffer, cx| {
25266                buffer.group_until_transaction(transaction, cx);
25267            });
25268        }
25269
25270        self.unmark_text(window, cx);
25271    }
25272
25273    fn replace_and_mark_text_in_range(
25274        &mut self,
25275        range_utf16: Option<Range<usize>>,
25276        text: &str,
25277        new_selected_range_utf16: Option<Range<usize>>,
25278        window: &mut Window,
25279        cx: &mut Context<Self>,
25280    ) {
25281        if !self.input_enabled {
25282            return;
25283        }
25284
25285        let transaction = self.transact(window, cx, |this, window, cx| {
25286            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25287                let snapshot = this.buffer.read(cx).read(cx);
25288                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25289                    for marked_range in &mut marked_ranges {
25290                        marked_range.end = marked_range.start + relative_range_utf16.end;
25291                        marked_range.start += relative_range_utf16.start;
25292                        marked_range.start =
25293                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25294                        marked_range.end =
25295                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25296                    }
25297                }
25298                Some(marked_ranges)
25299            } else if let Some(range_utf16) = range_utf16 {
25300                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25301                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25302                Some(this.selection_replacement_ranges(range_utf16, cx))
25303            } else {
25304                None
25305            };
25306
25307            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25308                let newest_selection_id = this.selections.newest_anchor().id;
25309                this.selections
25310                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25311                    .iter()
25312                    .zip(ranges_to_replace.iter())
25313                    .find_map(|(selection, range)| {
25314                        if selection.id == newest_selection_id {
25315                            Some(
25316                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25317                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25318                            )
25319                        } else {
25320                            None
25321                        }
25322                    })
25323            });
25324
25325            cx.emit(EditorEvent::InputHandled {
25326                utf16_range_to_replace: range_to_replace,
25327                text: text.into(),
25328            });
25329
25330            if let Some(ranges) = ranges_to_replace {
25331                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25332                    s.select_ranges(ranges)
25333                });
25334            }
25335
25336            let marked_ranges = {
25337                let snapshot = this.buffer.read(cx).read(cx);
25338                this.selections
25339                    .disjoint_anchors_arc()
25340                    .iter()
25341                    .map(|selection| {
25342                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25343                    })
25344                    .collect::<Vec<_>>()
25345            };
25346
25347            if text.is_empty() {
25348                this.unmark_text(window, cx);
25349            } else {
25350                this.highlight_text::<InputComposition>(
25351                    marked_ranges.clone(),
25352                    HighlightStyle {
25353                        underline: Some(UnderlineStyle {
25354                            thickness: px(1.),
25355                            color: None,
25356                            wavy: false,
25357                        }),
25358                        ..Default::default()
25359                    },
25360                    cx,
25361                );
25362            }
25363
25364            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25365            let use_autoclose = this.use_autoclose;
25366            let use_auto_surround = this.use_auto_surround;
25367            this.set_use_autoclose(false);
25368            this.set_use_auto_surround(false);
25369            this.handle_input(text, window, cx);
25370            this.set_use_autoclose(use_autoclose);
25371            this.set_use_auto_surround(use_auto_surround);
25372
25373            if let Some(new_selected_range) = new_selected_range_utf16 {
25374                let snapshot = this.buffer.read(cx).read(cx);
25375                let new_selected_ranges = marked_ranges
25376                    .into_iter()
25377                    .map(|marked_range| {
25378                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25379                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25380                            insertion_start.0 + new_selected_range.start,
25381                        ));
25382                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25383                            insertion_start.0 + new_selected_range.end,
25384                        ));
25385                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25386                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25387                    })
25388                    .collect::<Vec<_>>();
25389
25390                drop(snapshot);
25391                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25392                    selections.select_ranges(new_selected_ranges)
25393                });
25394            }
25395        });
25396
25397        self.ime_transaction = self.ime_transaction.or(transaction);
25398        if let Some(transaction) = self.ime_transaction {
25399            self.buffer.update(cx, |buffer, cx| {
25400                buffer.group_until_transaction(transaction, cx);
25401            });
25402        }
25403
25404        if self.text_highlights::<InputComposition>(cx).is_none() {
25405            self.ime_transaction.take();
25406        }
25407    }
25408
25409    fn bounds_for_range(
25410        &mut self,
25411        range_utf16: Range<usize>,
25412        element_bounds: gpui::Bounds<Pixels>,
25413        window: &mut Window,
25414        cx: &mut Context<Self>,
25415    ) -> Option<gpui::Bounds<Pixels>> {
25416        let text_layout_details = self.text_layout_details(window);
25417        let CharacterDimensions {
25418            em_width,
25419            em_advance,
25420            line_height,
25421        } = self.character_dimensions(window);
25422
25423        let snapshot = self.snapshot(window, cx);
25424        let scroll_position = snapshot.scroll_position();
25425        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25426
25427        let start =
25428            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25429        let x = Pixels::from(
25430            ScrollOffset::from(
25431                snapshot.x_for_display_point(start, &text_layout_details)
25432                    + self.gutter_dimensions.full_width(),
25433            ) - scroll_left,
25434        );
25435        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25436
25437        Some(Bounds {
25438            origin: element_bounds.origin + point(x, y),
25439            size: size(em_width, line_height),
25440        })
25441    }
25442
25443    fn character_index_for_point(
25444        &mut self,
25445        point: gpui::Point<Pixels>,
25446        _window: &mut Window,
25447        _cx: &mut Context<Self>,
25448    ) -> Option<usize> {
25449        let position_map = self.last_position_map.as_ref()?;
25450        if !position_map.text_hitbox.contains(&point) {
25451            return None;
25452        }
25453        let display_point = position_map.point_for_position(point).previous_valid;
25454        let anchor = position_map
25455            .snapshot
25456            .display_point_to_anchor(display_point, Bias::Left);
25457        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25458        Some(utf16_offset.0.0)
25459    }
25460
25461    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25462        self.input_enabled
25463    }
25464}
25465
25466trait SelectionExt {
25467    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25468    fn spanned_rows(
25469        &self,
25470        include_end_if_at_line_start: bool,
25471        map: &DisplaySnapshot,
25472    ) -> Range<MultiBufferRow>;
25473}
25474
25475impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25476    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25477        let start = self
25478            .start
25479            .to_point(map.buffer_snapshot())
25480            .to_display_point(map);
25481        let end = self
25482            .end
25483            .to_point(map.buffer_snapshot())
25484            .to_display_point(map);
25485        if self.reversed {
25486            end..start
25487        } else {
25488            start..end
25489        }
25490    }
25491
25492    fn spanned_rows(
25493        &self,
25494        include_end_if_at_line_start: bool,
25495        map: &DisplaySnapshot,
25496    ) -> Range<MultiBufferRow> {
25497        let start = self.start.to_point(map.buffer_snapshot());
25498        let mut end = self.end.to_point(map.buffer_snapshot());
25499        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25500            end.row -= 1;
25501        }
25502
25503        let buffer_start = map.prev_line_boundary(start).0;
25504        let buffer_end = map.next_line_boundary(end).0;
25505        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25506    }
25507}
25508
25509impl<T: InvalidationRegion> InvalidationStack<T> {
25510    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25511    where
25512        S: Clone + ToOffset,
25513    {
25514        while let Some(region) = self.last() {
25515            let all_selections_inside_invalidation_ranges =
25516                if selections.len() == region.ranges().len() {
25517                    selections
25518                        .iter()
25519                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25520                        .all(|(selection, invalidation_range)| {
25521                            let head = selection.head().to_offset(buffer);
25522                            invalidation_range.start <= head && invalidation_range.end >= head
25523                        })
25524                } else {
25525                    false
25526                };
25527
25528            if all_selections_inside_invalidation_ranges {
25529                break;
25530            } else {
25531                self.pop();
25532            }
25533        }
25534    }
25535}
25536
25537impl<T> Default for InvalidationStack<T> {
25538    fn default() -> Self {
25539        Self(Default::default())
25540    }
25541}
25542
25543impl<T> Deref for InvalidationStack<T> {
25544    type Target = Vec<T>;
25545
25546    fn deref(&self) -> &Self::Target {
25547        &self.0
25548    }
25549}
25550
25551impl<T> DerefMut for InvalidationStack<T> {
25552    fn deref_mut(&mut self) -> &mut Self::Target {
25553        &mut self.0
25554    }
25555}
25556
25557impl InvalidationRegion for SnippetState {
25558    fn ranges(&self) -> &[Range<Anchor>] {
25559        &self.ranges[self.active_index]
25560    }
25561}
25562
25563fn edit_prediction_edit_text(
25564    current_snapshot: &BufferSnapshot,
25565    edits: &[(Range<Anchor>, impl AsRef<str>)],
25566    edit_preview: &EditPreview,
25567    include_deletions: bool,
25568    cx: &App,
25569) -> HighlightedText {
25570    let edits = edits
25571        .iter()
25572        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25573        .collect::<Vec<_>>();
25574
25575    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25576}
25577
25578fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25579    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25580    // Just show the raw edit text with basic styling
25581    let mut text = String::new();
25582    let mut highlights = Vec::new();
25583
25584    let insertion_highlight_style = HighlightStyle {
25585        color: Some(cx.theme().colors().text),
25586        ..Default::default()
25587    };
25588
25589    for (_, edit_text) in edits {
25590        let start_offset = text.len();
25591        text.push_str(edit_text);
25592        let end_offset = text.len();
25593
25594        if start_offset < end_offset {
25595            highlights.push((start_offset..end_offset, insertion_highlight_style));
25596        }
25597    }
25598
25599    HighlightedText {
25600        text: text.into(),
25601        highlights,
25602    }
25603}
25604
25605pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25606    match severity {
25607        lsp::DiagnosticSeverity::ERROR => colors.error,
25608        lsp::DiagnosticSeverity::WARNING => colors.warning,
25609        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25610        lsp::DiagnosticSeverity::HINT => colors.info,
25611        _ => colors.ignored,
25612    }
25613}
25614
25615pub fn styled_runs_for_code_label<'a>(
25616    label: &'a CodeLabel,
25617    syntax_theme: &'a theme::SyntaxTheme,
25618    local_player: &'a theme::PlayerColor,
25619) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25620    let fade_out = HighlightStyle {
25621        fade_out: Some(0.35),
25622        ..Default::default()
25623    };
25624
25625    let mut prev_end = label.filter_range.end;
25626    label
25627        .runs
25628        .iter()
25629        .enumerate()
25630        .flat_map(move |(ix, (range, highlight_id))| {
25631            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25632                HighlightStyle {
25633                    color: Some(local_player.cursor),
25634                    ..Default::default()
25635                }
25636            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25637                HighlightStyle {
25638                    background_color: Some(local_player.selection),
25639                    ..Default::default()
25640                }
25641            } else if let Some(style) = highlight_id.style(syntax_theme) {
25642                style
25643            } else {
25644                return Default::default();
25645            };
25646            let muted_style = style.highlight(fade_out);
25647
25648            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25649            if range.start >= label.filter_range.end {
25650                if range.start > prev_end {
25651                    runs.push((prev_end..range.start, fade_out));
25652                }
25653                runs.push((range.clone(), muted_style));
25654            } else if range.end <= label.filter_range.end {
25655                runs.push((range.clone(), style));
25656            } else {
25657                runs.push((range.start..label.filter_range.end, style));
25658                runs.push((label.filter_range.end..range.end, muted_style));
25659            }
25660            prev_end = cmp::max(prev_end, range.end);
25661
25662            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25663                runs.push((prev_end..label.text.len(), fade_out));
25664            }
25665
25666            runs
25667        })
25668}
25669
25670pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25671    let mut prev_index = 0;
25672    let mut prev_codepoint: Option<char> = None;
25673    text.char_indices()
25674        .chain([(text.len(), '\0')])
25675        .filter_map(move |(index, codepoint)| {
25676            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25677            let is_boundary = index == text.len()
25678                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25679                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25680            if is_boundary {
25681                let chunk = &text[prev_index..index];
25682                prev_index = index;
25683                Some(chunk)
25684            } else {
25685                None
25686            }
25687        })
25688}
25689
25690/// Given a string of text immediately before the cursor, iterates over possible
25691/// strings a snippet could match to. More precisely: returns an iterator over
25692/// suffixes of `text` created by splitting at word boundaries (before & after
25693/// every non-word character).
25694///
25695/// Shorter suffixes are returned first.
25696pub(crate) fn snippet_candidate_suffixes(
25697    text: &str,
25698    is_word_char: impl Fn(char) -> bool,
25699) -> impl std::iter::Iterator<Item = &str> {
25700    let mut prev_index = text.len();
25701    let mut prev_codepoint = None;
25702    text.char_indices()
25703        .rev()
25704        .chain([(0, '\0')])
25705        .filter_map(move |(index, codepoint)| {
25706            let prev_index = std::mem::replace(&mut prev_index, index);
25707            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25708            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25709                None
25710            } else {
25711                let chunk = &text[prev_index..]; // go to end of string
25712                Some(chunk)
25713            }
25714        })
25715}
25716
25717pub trait RangeToAnchorExt: Sized {
25718    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25719
25720    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25721        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25722        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25723    }
25724}
25725
25726impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25727    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25728        let start_offset = self.start.to_offset(snapshot);
25729        let end_offset = self.end.to_offset(snapshot);
25730        if start_offset == end_offset {
25731            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25732        } else {
25733            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25734        }
25735    }
25736}
25737
25738pub trait RowExt {
25739    fn as_f64(&self) -> f64;
25740
25741    fn next_row(&self) -> Self;
25742
25743    fn previous_row(&self) -> Self;
25744
25745    fn minus(&self, other: Self) -> u32;
25746}
25747
25748impl RowExt for DisplayRow {
25749    fn as_f64(&self) -> f64 {
25750        self.0 as _
25751    }
25752
25753    fn next_row(&self) -> Self {
25754        Self(self.0 + 1)
25755    }
25756
25757    fn previous_row(&self) -> Self {
25758        Self(self.0.saturating_sub(1))
25759    }
25760
25761    fn minus(&self, other: Self) -> u32 {
25762        self.0 - other.0
25763    }
25764}
25765
25766impl RowExt for MultiBufferRow {
25767    fn as_f64(&self) -> f64 {
25768        self.0 as _
25769    }
25770
25771    fn next_row(&self) -> Self {
25772        Self(self.0 + 1)
25773    }
25774
25775    fn previous_row(&self) -> Self {
25776        Self(self.0.saturating_sub(1))
25777    }
25778
25779    fn minus(&self, other: Self) -> u32 {
25780        self.0 - other.0
25781    }
25782}
25783
25784trait RowRangeExt {
25785    type Row;
25786
25787    fn len(&self) -> usize;
25788
25789    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25790}
25791
25792impl RowRangeExt for Range<MultiBufferRow> {
25793    type Row = MultiBufferRow;
25794
25795    fn len(&self) -> usize {
25796        (self.end.0 - self.start.0) as usize
25797    }
25798
25799    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25800        (self.start.0..self.end.0).map(MultiBufferRow)
25801    }
25802}
25803
25804impl RowRangeExt for Range<DisplayRow> {
25805    type Row = DisplayRow;
25806
25807    fn len(&self) -> usize {
25808        (self.end.0 - self.start.0) as usize
25809    }
25810
25811    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25812        (self.start.0..self.end.0).map(DisplayRow)
25813    }
25814}
25815
25816/// If select range has more than one line, we
25817/// just point the cursor to range.start.
25818fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25819    if range.start.row == range.end.row {
25820        range
25821    } else {
25822        range.start..range.start
25823    }
25824}
25825pub struct KillRing(ClipboardItem);
25826impl Global for KillRing {}
25827
25828const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25829
25830enum BreakpointPromptEditAction {
25831    Log,
25832    Condition,
25833    HitCondition,
25834}
25835
25836struct BreakpointPromptEditor {
25837    pub(crate) prompt: Entity<Editor>,
25838    editor: WeakEntity<Editor>,
25839    breakpoint_anchor: Anchor,
25840    breakpoint: Breakpoint,
25841    edit_action: BreakpointPromptEditAction,
25842    block_ids: HashSet<CustomBlockId>,
25843    editor_margins: Arc<Mutex<EditorMargins>>,
25844    _subscriptions: Vec<Subscription>,
25845}
25846
25847impl BreakpointPromptEditor {
25848    const MAX_LINES: u8 = 4;
25849
25850    fn new(
25851        editor: WeakEntity<Editor>,
25852        breakpoint_anchor: Anchor,
25853        breakpoint: Breakpoint,
25854        edit_action: BreakpointPromptEditAction,
25855        window: &mut Window,
25856        cx: &mut Context<Self>,
25857    ) -> Self {
25858        let base_text = match edit_action {
25859            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25860            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25861            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25862        }
25863        .map(|msg| msg.to_string())
25864        .unwrap_or_default();
25865
25866        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25867        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25868
25869        let prompt = cx.new(|cx| {
25870            let mut prompt = Editor::new(
25871                EditorMode::AutoHeight {
25872                    min_lines: 1,
25873                    max_lines: Some(Self::MAX_LINES as usize),
25874                },
25875                buffer,
25876                None,
25877                window,
25878                cx,
25879            );
25880            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25881            prompt.set_show_cursor_when_unfocused(false, cx);
25882            prompt.set_placeholder_text(
25883                match edit_action {
25884                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25885                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25886                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25887                },
25888                window,
25889                cx,
25890            );
25891
25892            prompt
25893        });
25894
25895        Self {
25896            prompt,
25897            editor,
25898            breakpoint_anchor,
25899            breakpoint,
25900            edit_action,
25901            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25902            block_ids: Default::default(),
25903            _subscriptions: vec![],
25904        }
25905    }
25906
25907    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25908        self.block_ids.extend(block_ids)
25909    }
25910
25911    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25912        if let Some(editor) = self.editor.upgrade() {
25913            let message = self
25914                .prompt
25915                .read(cx)
25916                .buffer
25917                .read(cx)
25918                .as_singleton()
25919                .expect("A multi buffer in breakpoint prompt isn't possible")
25920                .read(cx)
25921                .as_rope()
25922                .to_string();
25923
25924            editor.update(cx, |editor, cx| {
25925                editor.edit_breakpoint_at_anchor(
25926                    self.breakpoint_anchor,
25927                    self.breakpoint.clone(),
25928                    match self.edit_action {
25929                        BreakpointPromptEditAction::Log => {
25930                            BreakpointEditAction::EditLogMessage(message.into())
25931                        }
25932                        BreakpointPromptEditAction::Condition => {
25933                            BreakpointEditAction::EditCondition(message.into())
25934                        }
25935                        BreakpointPromptEditAction::HitCondition => {
25936                            BreakpointEditAction::EditHitCondition(message.into())
25937                        }
25938                    },
25939                    cx,
25940                );
25941
25942                editor.remove_blocks(self.block_ids.clone(), None, cx);
25943                cx.focus_self(window);
25944            });
25945        }
25946    }
25947
25948    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25949        self.editor
25950            .update(cx, |editor, cx| {
25951                editor.remove_blocks(self.block_ids.clone(), None, cx);
25952                window.focus(&editor.focus_handle, cx);
25953            })
25954            .log_err();
25955    }
25956
25957    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25958        let settings = ThemeSettings::get_global(cx);
25959        let text_style = TextStyle {
25960            color: if self.prompt.read(cx).read_only(cx) {
25961                cx.theme().colors().text_disabled
25962            } else {
25963                cx.theme().colors().text
25964            },
25965            font_family: settings.buffer_font.family.clone(),
25966            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25967            font_size: settings.buffer_font_size(cx).into(),
25968            font_weight: settings.buffer_font.weight,
25969            line_height: relative(settings.buffer_line_height.value()),
25970            ..Default::default()
25971        };
25972        EditorElement::new(
25973            &self.prompt,
25974            EditorStyle {
25975                background: cx.theme().colors().editor_background,
25976                local_player: cx.theme().players().local(),
25977                text: text_style,
25978                ..Default::default()
25979            },
25980        )
25981    }
25982}
25983
25984impl Render for BreakpointPromptEditor {
25985    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25986        let editor_margins = *self.editor_margins.lock();
25987        let gutter_dimensions = editor_margins.gutter;
25988        h_flex()
25989            .key_context("Editor")
25990            .bg(cx.theme().colors().editor_background)
25991            .border_y_1()
25992            .border_color(cx.theme().status().info_border)
25993            .size_full()
25994            .py(window.line_height() / 2.5)
25995            .on_action(cx.listener(Self::confirm))
25996            .on_action(cx.listener(Self::cancel))
25997            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25998            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25999    }
26000}
26001
26002impl Focusable for BreakpointPromptEditor {
26003    fn focus_handle(&self, cx: &App) -> FocusHandle {
26004        self.prompt.focus_handle(cx)
26005    }
26006}
26007
26008fn all_edits_insertions_or_deletions(
26009    edits: &Vec<(Range<Anchor>, Arc<str>)>,
26010    snapshot: &MultiBufferSnapshot,
26011) -> bool {
26012    let mut all_insertions = true;
26013    let mut all_deletions = true;
26014
26015    for (range, new_text) in edits.iter() {
26016        let range_is_empty = range.to_offset(snapshot).is_empty();
26017        let text_is_empty = new_text.is_empty();
26018
26019        if range_is_empty != text_is_empty {
26020            if range_is_empty {
26021                all_deletions = false;
26022            } else {
26023                all_insertions = false;
26024            }
26025        } else {
26026            return false;
26027        }
26028
26029        if !all_insertions && !all_deletions {
26030            return false;
26031        }
26032    }
26033    all_insertions || all_deletions
26034}
26035
26036struct MissingEditPredictionKeybindingTooltip;
26037
26038impl Render for MissingEditPredictionKeybindingTooltip {
26039    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26040        ui::tooltip_container(cx, |container, cx| {
26041            container
26042                .flex_shrink_0()
26043                .max_w_80()
26044                .min_h(rems_from_px(124.))
26045                .justify_between()
26046                .child(
26047                    v_flex()
26048                        .flex_1()
26049                        .text_ui_sm(cx)
26050                        .child(Label::new("Conflict with Accept Keybinding"))
26051                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
26052                )
26053                .child(
26054                    h_flex()
26055                        .pb_1()
26056                        .gap_1()
26057                        .items_end()
26058                        .w_full()
26059                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
26060                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
26061                        }))
26062                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
26063                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
26064                        })),
26065                )
26066        })
26067    }
26068}
26069
26070#[derive(Debug, Clone, Copy, PartialEq)]
26071pub struct LineHighlight {
26072    pub background: Background,
26073    pub border: Option<gpui::Hsla>,
26074    pub include_gutter: bool,
26075    pub type_id: Option<TypeId>,
26076}
26077
26078struct LineManipulationResult {
26079    pub new_text: String,
26080    pub line_count_before: usize,
26081    pub line_count_after: usize,
26082}
26083
26084fn render_diff_hunk_controls(
26085    row: u32,
26086    status: &DiffHunkStatus,
26087    hunk_range: Range<Anchor>,
26088    is_created_file: bool,
26089    line_height: Pixels,
26090    editor: &Entity<Editor>,
26091    _window: &mut Window,
26092    cx: &mut App,
26093) -> AnyElement {
26094    h_flex()
26095        .h(line_height)
26096        .mr_1()
26097        .gap_1()
26098        .px_0p5()
26099        .pb_1()
26100        .border_x_1()
26101        .border_b_1()
26102        .border_color(cx.theme().colors().border_variant)
26103        .rounded_b_lg()
26104        .bg(cx.theme().colors().editor_background)
26105        .gap_1()
26106        .block_mouse_except_scroll()
26107        .shadow_md()
26108        .child(if status.has_secondary_hunk() {
26109            Button::new(("stage", row as u64), "Stage")
26110                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26111                .tooltip({
26112                    let focus_handle = editor.focus_handle(cx);
26113                    move |_window, cx| {
26114                        Tooltip::for_action_in(
26115                            "Stage Hunk",
26116                            &::git::ToggleStaged,
26117                            &focus_handle,
26118                            cx,
26119                        )
26120                    }
26121                })
26122                .on_click({
26123                    let editor = editor.clone();
26124                    move |_event, _window, cx| {
26125                        editor.update(cx, |editor, cx| {
26126                            editor.stage_or_unstage_diff_hunks(
26127                                true,
26128                                vec![hunk_range.start..hunk_range.start],
26129                                cx,
26130                            );
26131                        });
26132                    }
26133                })
26134        } else {
26135            Button::new(("unstage", row as u64), "Unstage")
26136                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26137                .tooltip({
26138                    let focus_handle = editor.focus_handle(cx);
26139                    move |_window, cx| {
26140                        Tooltip::for_action_in(
26141                            "Unstage Hunk",
26142                            &::git::ToggleStaged,
26143                            &focus_handle,
26144                            cx,
26145                        )
26146                    }
26147                })
26148                .on_click({
26149                    let editor = editor.clone();
26150                    move |_event, _window, cx| {
26151                        editor.update(cx, |editor, cx| {
26152                            editor.stage_or_unstage_diff_hunks(
26153                                false,
26154                                vec![hunk_range.start..hunk_range.start],
26155                                cx,
26156                            );
26157                        });
26158                    }
26159                })
26160        })
26161        .child(
26162            Button::new(("restore", row as u64), "Restore")
26163                .tooltip({
26164                    let focus_handle = editor.focus_handle(cx);
26165                    move |_window, cx| {
26166                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26167                    }
26168                })
26169                .on_click({
26170                    let editor = editor.clone();
26171                    move |_event, window, cx| {
26172                        editor.update(cx, |editor, cx| {
26173                            let snapshot = editor.snapshot(window, cx);
26174                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26175                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26176                        });
26177                    }
26178                })
26179                .disabled(is_created_file),
26180        )
26181        .when(
26182            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26183            |el| {
26184                el.child(
26185                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26186                        .shape(IconButtonShape::Square)
26187                        .icon_size(IconSize::Small)
26188                        // .disabled(!has_multiple_hunks)
26189                        .tooltip({
26190                            let focus_handle = editor.focus_handle(cx);
26191                            move |_window, cx| {
26192                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26193                            }
26194                        })
26195                        .on_click({
26196                            let editor = editor.clone();
26197                            move |_event, window, cx| {
26198                                editor.update(cx, |editor, cx| {
26199                                    let snapshot = editor.snapshot(window, cx);
26200                                    let position =
26201                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26202                                    editor.go_to_hunk_before_or_after_position(
26203                                        &snapshot,
26204                                        position,
26205                                        Direction::Next,
26206                                        window,
26207                                        cx,
26208                                    );
26209                                    editor.expand_selected_diff_hunks(cx);
26210                                });
26211                            }
26212                        }),
26213                )
26214                .child(
26215                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26216                        .shape(IconButtonShape::Square)
26217                        .icon_size(IconSize::Small)
26218                        // .disabled(!has_multiple_hunks)
26219                        .tooltip({
26220                            let focus_handle = editor.focus_handle(cx);
26221                            move |_window, cx| {
26222                                Tooltip::for_action_in(
26223                                    "Previous Hunk",
26224                                    &GoToPreviousHunk,
26225                                    &focus_handle,
26226                                    cx,
26227                                )
26228                            }
26229                        })
26230                        .on_click({
26231                            let editor = editor.clone();
26232                            move |_event, window, cx| {
26233                                editor.update(cx, |editor, cx| {
26234                                    let snapshot = editor.snapshot(window, cx);
26235                                    let point =
26236                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26237                                    editor.go_to_hunk_before_or_after_position(
26238                                        &snapshot,
26239                                        point,
26240                                        Direction::Prev,
26241                                        window,
26242                                        cx,
26243                                    );
26244                                    editor.expand_selected_diff_hunks(cx);
26245                                });
26246                            }
26247                        }),
26248                )
26249            },
26250        )
26251        .into_any_element()
26252}
26253
26254pub fn multibuffer_context_lines(cx: &App) -> u32 {
26255    EditorSettings::try_get(cx)
26256        .map(|settings| settings.excerpt_context_lines)
26257        .unwrap_or(2)
26258        .min(32)
26259}