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    render_breadcrumb_text,
   62};
   63pub use git::blame::BlameRenderer;
   64pub use hover_popover::hover_markdown_style;
   65pub use inlays::Inlay;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   71    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   72    ToPoint,
   73};
   74pub use split::SplittableEditor;
   75pub use text::Bias;
   76
   77use ::git::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus};
   78use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   79use anyhow::{Context as _, Result, anyhow, bail};
   80use blink_manager::BlinkManager;
   81use buffer_diff::DiffHunkStatus;
   82use client::{Collaborator, ParticipantIndex, parse_zed_link};
   83use clock::ReplicaId;
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   89use convert_case::{Case, Casing};
   90use dap::TelemetrySpawnLocation;
   91use display_map::*;
   92use edit_prediction_types::{
   93    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionGranularity,
   94};
   95use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   96use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   97use futures::{
   98    FutureExt, StreamExt as _,
   99    future::{self, Shared, join},
  100    stream::FuturesUnordered,
  101};
  102use fuzzy::{StringMatch, StringMatchCandidate};
  103use git::blame::{GitBlame, GlobalBlameRenderer};
  104use gpui::{
  105    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  106    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  107    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  108    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  109    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage,
  110    Render, ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextRun,
  111    TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle,
  112    WeakEntity, WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative,
  113    size,
  114};
  115use hover_links::{HoverLink, HoveredLinkState, find_file};
  116use hover_popover::{HoverState, hide_hover};
  117use indent_guides::ActiveIndentGuidesState;
  118use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  119use itertools::{Either, Itertools};
  120use language::{
  121    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  122    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  123    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  124    IndentSize, Language, LanguageName, LanguageRegistry, LanguageScope, OffsetRangeExt,
  125    OutlineItem, Point, Runnable, Selection, SelectionGoal, TextObject, TransactionId,
  126    TreeSitterOptions, WordsQuery,
  127    language_settings::{
  128        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  129        all_language_settings, language_settings,
  130    },
  131    point_from_lsp, point_to_lsp, text_diff_with_options,
  132};
  133use linked_editing_ranges::refresh_linked_ranges;
  134use lsp::{
  135    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  136    LanguageServerId,
  137};
  138use lsp_colors::LspColorData;
  139use markdown::Markdown;
  140use mouse_context_menu::MouseContextMenu;
  141use movement::TextLayoutDetails;
  142use multi_buffer::{
  143    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  144};
  145use parking_lot::Mutex;
  146use persistence::DB;
  147use project::{
  148    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  149    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  150    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  151    ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  152    debugger::{
  153        breakpoint_store::{
  154            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  155            BreakpointStore, BreakpointStoreEvent,
  156        },
  157        session::{Session, SessionEvent},
  158    },
  159    git_store::GitStoreEvent,
  160    lsp_store::{
  161        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  162        OpenLspBufferHandle,
  163    },
  164    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  165};
  166use rand::seq::SliceRandom;
  167use regex::Regex;
  168use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  169use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  170use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  171use serde::{Deserialize, Serialize};
  172use settings::{
  173    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  174    update_settings_file,
  175};
  176use smallvec::{SmallVec, smallvec};
  177use snippet::Snippet;
  178use std::{
  179    any::{Any, TypeId},
  180    borrow::Cow,
  181    cell::{OnceCell, RefCell},
  182    cmp::{self, Ordering, Reverse},
  183    collections::hash_map,
  184    iter::{self, Peekable},
  185    mem,
  186    num::NonZeroU32,
  187    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  188    path::{Path, PathBuf},
  189    rc::Rc,
  190    sync::Arc,
  191    time::{Duration, Instant},
  192};
  193use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  195use theme::{
  196    AccentColors, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  202};
  203use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  204use workspace::{
  205    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  206    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  207    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  208    item::{BreadcrumbText, ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::{CollapseDirection, SearchEvent},
  211};
  212
  213use crate::{
  214    code_context_menus::CompletionsMenuSource,
  215    editor_settings::MultiCursorModifier,
  216    hover_links::{find_url, find_url_from_range},
  217    inlays::{
  218        InlineValueCache,
  219        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  220    },
  221    scroll::{ScrollOffset, ScrollPixelOffset},
  222    selections_collection::resolve_selections_wrapping_blocks,
  223    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  224};
  225
  226pub const FILE_HEADER_HEIGHT: u32 = 2;
  227pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  228const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  229const MAX_LINE_LEN: usize = 1024;
  230const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  231const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  232pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  233#[doc(hidden)]
  234pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  235pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  236
  237pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  238pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  240pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  241
  242pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  243pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  244pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  245
  246pub type RenderDiffHunkControlsFn = Arc<
  247    dyn Fn(
  248        u32,
  249        &DiffHunkStatus,
  250        Range<Anchor>,
  251        bool,
  252        Pixels,
  253        &Entity<Editor>,
  254        &mut Window,
  255        &mut App,
  256    ) -> AnyElement,
  257>;
  258
  259enum ReportEditorEvent {
  260    Saved { auto_saved: bool },
  261    EditorOpened,
  262    Closed,
  263}
  264
  265impl ReportEditorEvent {
  266    pub fn event_type(&self) -> &'static str {
  267        match self {
  268            Self::Saved { .. } => "Editor Saved",
  269            Self::EditorOpened => "Editor Opened",
  270            Self::Closed => "Editor Closed",
  271        }
  272    }
  273}
  274
  275pub enum ActiveDebugLine {}
  276pub enum DebugStackFrameLine {}
  277enum DocumentHighlightRead {}
  278enum DocumentHighlightWrite {}
  279enum InputComposition {}
  280pub enum PendingInput {}
  281enum SelectedTextHighlight {}
  282
  283pub enum ConflictsOuter {}
  284pub enum ConflictsOurs {}
  285pub enum ConflictsTheirs {}
  286pub enum ConflictsOursMarker {}
  287pub enum ConflictsTheirsMarker {}
  288
  289pub struct HunkAddedColor;
  290pub struct HunkRemovedColor;
  291
  292#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  293pub enum Navigated {
  294    Yes,
  295    No,
  296}
  297
  298impl Navigated {
  299    pub fn from_bool(yes: bool) -> Navigated {
  300        if yes { Navigated::Yes } else { Navigated::No }
  301    }
  302}
  303
  304#[derive(Debug, Clone, PartialEq, Eq)]
  305enum DisplayDiffHunk {
  306    Folded {
  307        display_row: DisplayRow,
  308    },
  309    Unfolded {
  310        is_created_file: bool,
  311        diff_base_byte_range: Range<usize>,
  312        display_row_range: Range<DisplayRow>,
  313        multi_buffer_range: Range<Anchor>,
  314        status: DiffHunkStatus,
  315        word_diffs: Vec<Range<MultiBufferOffset>>,
  316    },
  317}
  318
  319pub enum HideMouseCursorOrigin {
  320    TypingAction,
  321    MovementAction,
  322}
  323
  324pub fn init(cx: &mut App) {
  325    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  326
  327    workspace::register_project_item::<Editor>(cx);
  328    workspace::FollowableViewRegistry::register::<Editor>(cx);
  329    workspace::register_serializable_item::<Editor>(cx);
  330
  331    cx.observe_new(
  332        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  333            workspace.register_action(Editor::new_file);
  334            workspace.register_action(Editor::new_file_split);
  335            workspace.register_action(Editor::new_file_vertical);
  336            workspace.register_action(Editor::new_file_horizontal);
  337            workspace.register_action(Editor::cancel_language_server_work);
  338            workspace.register_action(Editor::toggle_focus);
  339        },
  340    )
  341    .detach();
  342
  343    cx.on_action(move |_: &workspace::NewFile, cx| {
  344        let app_state = workspace::AppState::global(cx);
  345        if let Some(app_state) = app_state.upgrade() {
  346            workspace::open_new(
  347                Default::default(),
  348                app_state,
  349                cx,
  350                |workspace, window, cx| {
  351                    Editor::new_file(workspace, &Default::default(), window, cx)
  352                },
  353            )
  354            .detach();
  355        }
  356    })
  357    .on_action(move |_: &workspace::NewWindow, cx| {
  358        let app_state = workspace::AppState::global(cx);
  359        if let Some(app_state) = app_state.upgrade() {
  360            workspace::open_new(
  361                Default::default(),
  362                app_state,
  363                cx,
  364                |workspace, window, cx| {
  365                    cx.activate(true);
  366                    Editor::new_file(workspace, &Default::default(), window, cx)
  367                },
  368            )
  369            .detach();
  370        }
  371    });
  372}
  373
  374pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  375    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  376}
  377
  378pub trait DiagnosticRenderer {
  379    fn render_group(
  380        &self,
  381        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  382        buffer_id: BufferId,
  383        snapshot: EditorSnapshot,
  384        editor: WeakEntity<Editor>,
  385        language_registry: Option<Arc<LanguageRegistry>>,
  386        cx: &mut App,
  387    ) -> Vec<BlockProperties<Anchor>>;
  388
  389    fn render_hover(
  390        &self,
  391        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  392        range: Range<Point>,
  393        buffer_id: BufferId,
  394        language_registry: Option<Arc<LanguageRegistry>>,
  395        cx: &mut App,
  396    ) -> Option<Entity<markdown::Markdown>>;
  397
  398    fn open_link(
  399        &self,
  400        editor: &mut Editor,
  401        link: SharedString,
  402        window: &mut Window,
  403        cx: &mut Context<Editor>,
  404    );
  405}
  406
  407pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  408
  409impl GlobalDiagnosticRenderer {
  410    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  411        cx.try_global::<Self>().map(|g| g.0.clone())
  412    }
  413}
  414
  415impl gpui::Global for GlobalDiagnosticRenderer {}
  416pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  417    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  418}
  419
  420pub struct SearchWithinRange;
  421
  422trait InvalidationRegion {
  423    fn ranges(&self) -> &[Range<Anchor>];
  424}
  425
  426#[derive(Clone, Debug, PartialEq)]
  427pub enum SelectPhase {
  428    Begin {
  429        position: DisplayPoint,
  430        add: bool,
  431        click_count: usize,
  432    },
  433    BeginColumnar {
  434        position: DisplayPoint,
  435        reset: bool,
  436        mode: ColumnarMode,
  437        goal_column: u32,
  438    },
  439    Extend {
  440        position: DisplayPoint,
  441        click_count: usize,
  442    },
  443    Update {
  444        position: DisplayPoint,
  445        goal_column: u32,
  446        scroll_delta: gpui::Point<f32>,
  447    },
  448    End,
  449}
  450
  451#[derive(Clone, Debug, PartialEq)]
  452pub enum ColumnarMode {
  453    FromMouse,
  454    FromSelection,
  455}
  456
  457#[derive(Clone, Debug)]
  458pub enum SelectMode {
  459    Character,
  460    Word(Range<Anchor>),
  461    Line(Range<Anchor>),
  462    All,
  463}
  464
  465#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  466pub enum SizingBehavior {
  467    /// The editor will layout itself using `size_full` and will include the vertical
  468    /// scroll margin as requested by user settings.
  469    #[default]
  470    Default,
  471    /// The editor will layout itself using `size_full`, but will not have any
  472    /// vertical overscroll.
  473    ExcludeOverscrollMargin,
  474    /// The editor will request a vertical size according to its content and will be
  475    /// layouted without a vertical scroll margin.
  476    SizeByContent,
  477}
  478
  479#[derive(Clone, PartialEq, Eq, Debug)]
  480pub enum EditorMode {
  481    SingleLine,
  482    AutoHeight {
  483        min_lines: usize,
  484        max_lines: Option<usize>,
  485    },
  486    Full {
  487        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  488        scale_ui_elements_with_buffer_font_size: bool,
  489        /// When set to `true`, the editor will render a background for the active line.
  490        show_active_line_background: bool,
  491        /// Determines the sizing behavior for this editor
  492        sizing_behavior: SizingBehavior,
  493    },
  494    Minimap {
  495        parent: WeakEntity<Editor>,
  496    },
  497}
  498
  499impl EditorMode {
  500    pub fn full() -> Self {
  501        Self::Full {
  502            scale_ui_elements_with_buffer_font_size: true,
  503            show_active_line_background: true,
  504            sizing_behavior: SizingBehavior::Default,
  505        }
  506    }
  507
  508    #[inline]
  509    pub fn is_full(&self) -> bool {
  510        matches!(self, Self::Full { .. })
  511    }
  512
  513    #[inline]
  514    pub fn is_single_line(&self) -> bool {
  515        matches!(self, Self::SingleLine { .. })
  516    }
  517
  518    #[inline]
  519    fn is_minimap(&self) -> bool {
  520        matches!(self, Self::Minimap { .. })
  521    }
  522}
  523
  524#[derive(Copy, Clone, Debug)]
  525pub enum SoftWrap {
  526    /// Prefer not to wrap at all.
  527    ///
  528    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  529    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  530    GitDiff,
  531    /// Prefer a single line generally, unless an overly long line is encountered.
  532    None,
  533    /// Soft wrap lines that exceed the editor width.
  534    EditorWidth,
  535    /// Soft wrap lines at the preferred line length.
  536    Column(u32),
  537    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  538    Bounded(u32),
  539}
  540
  541#[derive(Clone)]
  542pub struct EditorStyle {
  543    pub background: Hsla,
  544    pub border: Hsla,
  545    pub local_player: PlayerColor,
  546    pub text: TextStyle,
  547    pub scrollbar_width: Pixels,
  548    pub syntax: Arc<SyntaxTheme>,
  549    pub status: StatusColors,
  550    pub inlay_hints_style: HighlightStyle,
  551    pub edit_prediction_styles: EditPredictionStyles,
  552    pub unnecessary_code_fade: f32,
  553    pub show_underlines: bool,
  554}
  555
  556impl Default for EditorStyle {
  557    fn default() -> Self {
  558        Self {
  559            background: Hsla::default(),
  560            border: Hsla::default(),
  561            local_player: PlayerColor::default(),
  562            text: TextStyle::default(),
  563            scrollbar_width: Pixels::default(),
  564            syntax: Default::default(),
  565            // HACK: Status colors don't have a real default.
  566            // We should look into removing the status colors from the editor
  567            // style and retrieve them directly from the theme.
  568            status: StatusColors::dark(),
  569            inlay_hints_style: HighlightStyle::default(),
  570            edit_prediction_styles: EditPredictionStyles {
  571                insertion: HighlightStyle::default(),
  572                whitespace: HighlightStyle::default(),
  573            },
  574            unnecessary_code_fade: Default::default(),
  575            show_underlines: true,
  576        }
  577    }
  578}
  579
  580pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  581    let show_background = language_settings::language_settings(None, None, cx)
  582        .inlay_hints
  583        .show_background;
  584
  585    let mut style = cx.theme().syntax().get("hint");
  586
  587    if style.color.is_none() {
  588        style.color = Some(cx.theme().status().hint);
  589    }
  590
  591    if !show_background {
  592        style.background_color = None;
  593        return style;
  594    }
  595
  596    if style.background_color.is_none() {
  597        style.background_color = Some(cx.theme().status().hint_background);
  598    }
  599
  600    style
  601}
  602
  603pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  604    EditPredictionStyles {
  605        insertion: HighlightStyle {
  606            color: Some(cx.theme().status().predictive),
  607            ..HighlightStyle::default()
  608        },
  609        whitespace: HighlightStyle {
  610            background_color: Some(cx.theme().status().created_background),
  611            ..HighlightStyle::default()
  612        },
  613    }
  614}
  615
  616type CompletionId = usize;
  617
  618pub(crate) enum EditDisplayMode {
  619    TabAccept,
  620    DiffPopover,
  621    Inline,
  622}
  623
  624enum EditPrediction {
  625    Edit {
  626        edits: Vec<(Range<Anchor>, Arc<str>)>,
  627        edit_preview: Option<EditPreview>,
  628        display_mode: EditDisplayMode,
  629        snapshot: BufferSnapshot,
  630    },
  631    /// Move to a specific location in the active editor
  632    MoveWithin {
  633        target: Anchor,
  634        snapshot: BufferSnapshot,
  635    },
  636    /// Move to a specific location in a different editor (not the active one)
  637    MoveOutside {
  638        target: language::Anchor,
  639        snapshot: BufferSnapshot,
  640    },
  641}
  642
  643struct EditPredictionState {
  644    inlay_ids: Vec<InlayId>,
  645    completion: EditPrediction,
  646    completion_id: Option<SharedString>,
  647    invalidation_range: Option<Range<Anchor>>,
  648}
  649
  650enum EditPredictionSettings {
  651    Disabled,
  652    Enabled {
  653        show_in_menu: bool,
  654        preview_requires_modifier: bool,
  655    },
  656}
  657
  658enum EditPredictionHighlight {}
  659
  660#[derive(Debug, Clone)]
  661struct InlineDiagnostic {
  662    message: SharedString,
  663    group_id: usize,
  664    is_primary: bool,
  665    start: Point,
  666    severity: lsp::DiagnosticSeverity,
  667}
  668
  669pub enum MenuEditPredictionsPolicy {
  670    Never,
  671    ByProvider,
  672}
  673
  674pub enum EditPredictionPreview {
  675    /// Modifier is not pressed
  676    Inactive { released_too_fast: bool },
  677    /// Modifier pressed
  678    Active {
  679        since: Instant,
  680        previous_scroll_position: Option<ScrollAnchor>,
  681    },
  682}
  683
  684impl EditPredictionPreview {
  685    pub fn released_too_fast(&self) -> bool {
  686        match self {
  687            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  688            EditPredictionPreview::Active { .. } => false,
  689        }
  690    }
  691
  692    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  693        if let EditPredictionPreview::Active {
  694            previous_scroll_position,
  695            ..
  696        } = self
  697        {
  698            *previous_scroll_position = scroll_position;
  699        }
  700    }
  701}
  702
  703pub struct ContextMenuOptions {
  704    pub min_entries_visible: usize,
  705    pub max_entries_visible: usize,
  706    pub placement: Option<ContextMenuPlacement>,
  707}
  708
  709#[derive(Debug, Clone, PartialEq, Eq)]
  710pub enum ContextMenuPlacement {
  711    Above,
  712    Below,
  713}
  714
  715#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  716struct EditorActionId(usize);
  717
  718impl EditorActionId {
  719    pub fn post_inc(&mut self) -> Self {
  720        let answer = self.0;
  721
  722        *self = Self(answer + 1);
  723
  724        Self(answer)
  725    }
  726}
  727
  728// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  729// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  730
  731type BackgroundHighlight = (
  732    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  733    Arc<[Range<Anchor>]>,
  734);
  735type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  736
  737#[derive(Default)]
  738struct ScrollbarMarkerState {
  739    scrollbar_size: Size<Pixels>,
  740    dirty: bool,
  741    markers: Arc<[PaintQuad]>,
  742    pending_refresh: Option<Task<Result<()>>>,
  743}
  744
  745impl ScrollbarMarkerState {
  746    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  747        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  748    }
  749}
  750
  751#[derive(Clone, Copy, PartialEq, Eq)]
  752pub enum MinimapVisibility {
  753    Disabled,
  754    Enabled {
  755        /// The configuration currently present in the users settings.
  756        setting_configuration: bool,
  757        /// Whether to override the currently set visibility from the users setting.
  758        toggle_override: bool,
  759    },
  760}
  761
  762impl MinimapVisibility {
  763    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  764        if mode.is_full() {
  765            Self::Enabled {
  766                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  767                toggle_override: false,
  768            }
  769        } else {
  770            Self::Disabled
  771        }
  772    }
  773
  774    fn hidden(&self) -> Self {
  775        match *self {
  776            Self::Enabled {
  777                setting_configuration,
  778                ..
  779            } => Self::Enabled {
  780                setting_configuration,
  781                toggle_override: setting_configuration,
  782            },
  783            Self::Disabled => Self::Disabled,
  784        }
  785    }
  786
  787    fn disabled(&self) -> bool {
  788        matches!(*self, Self::Disabled)
  789    }
  790
  791    fn settings_visibility(&self) -> bool {
  792        match *self {
  793            Self::Enabled {
  794                setting_configuration,
  795                ..
  796            } => setting_configuration,
  797            _ => false,
  798        }
  799    }
  800
  801    fn visible(&self) -> bool {
  802        match *self {
  803            Self::Enabled {
  804                setting_configuration,
  805                toggle_override,
  806            } => setting_configuration ^ toggle_override,
  807            _ => false,
  808        }
  809    }
  810
  811    fn toggle_visibility(&self) -> Self {
  812        match *self {
  813            Self::Enabled {
  814                toggle_override,
  815                setting_configuration,
  816            } => Self::Enabled {
  817                setting_configuration,
  818                toggle_override: !toggle_override,
  819            },
  820            Self::Disabled => Self::Disabled,
  821        }
  822    }
  823}
  824
  825#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  826pub enum BufferSerialization {
  827    All,
  828    NonDirtyBuffers,
  829}
  830
  831impl BufferSerialization {
  832    fn new(restore_unsaved_buffers: bool) -> Self {
  833        if restore_unsaved_buffers {
  834            Self::All
  835        } else {
  836            Self::NonDirtyBuffers
  837        }
  838    }
  839}
  840
  841#[derive(Clone, Debug)]
  842struct RunnableTasks {
  843    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  844    offset: multi_buffer::Anchor,
  845    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  846    column: u32,
  847    // Values of all named captures, including those starting with '_'
  848    extra_variables: HashMap<String, String>,
  849    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  850    context_range: Range<BufferOffset>,
  851}
  852
  853impl RunnableTasks {
  854    fn resolve<'a>(
  855        &'a self,
  856        cx: &'a task::TaskContext,
  857    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  858        self.templates.iter().filter_map(|(kind, template)| {
  859            template
  860                .resolve_task(&kind.to_id_base(), cx)
  861                .map(|task| (kind.clone(), task))
  862        })
  863    }
  864}
  865
  866#[derive(Clone)]
  867pub struct ResolvedTasks {
  868    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  869    position: Anchor,
  870}
  871
  872/// Addons allow storing per-editor state in other crates (e.g. Vim)
  873pub trait Addon: 'static {
  874    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  875
  876    fn render_buffer_header_controls(
  877        &self,
  878        _: &ExcerptInfo,
  879        _: &Window,
  880        _: &App,
  881    ) -> Option<AnyElement> {
  882        None
  883    }
  884
  885    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  886        None
  887    }
  888
  889    fn to_any(&self) -> &dyn std::any::Any;
  890
  891    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  892        None
  893    }
  894}
  895
  896struct ChangeLocation {
  897    current: Option<Vec<Anchor>>,
  898    original: Vec<Anchor>,
  899}
  900impl ChangeLocation {
  901    fn locations(&self) -> &[Anchor] {
  902        self.current.as_ref().unwrap_or(&self.original)
  903    }
  904}
  905
  906/// A set of caret positions, registered when the editor was edited.
  907pub struct ChangeList {
  908    changes: Vec<ChangeLocation>,
  909    /// Currently "selected" change.
  910    position: Option<usize>,
  911}
  912
  913impl ChangeList {
  914    pub fn new() -> Self {
  915        Self {
  916            changes: Vec::new(),
  917            position: None,
  918        }
  919    }
  920
  921    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  922    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  923    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  924        if self.changes.is_empty() {
  925            return None;
  926        }
  927
  928        let prev = self.position.unwrap_or(self.changes.len());
  929        let next = if direction == Direction::Prev {
  930            prev.saturating_sub(count)
  931        } else {
  932            (prev + count).min(self.changes.len() - 1)
  933        };
  934        self.position = Some(next);
  935        self.changes.get(next).map(|change| change.locations())
  936    }
  937
  938    /// Adds a new change to the list, resetting the change list position.
  939    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  940        self.position.take();
  941        if let Some(last) = self.changes.last_mut()
  942            && group
  943        {
  944            last.current = Some(new_positions)
  945        } else {
  946            self.changes.push(ChangeLocation {
  947                original: new_positions,
  948                current: None,
  949            });
  950        }
  951    }
  952
  953    pub fn last(&self) -> Option<&[Anchor]> {
  954        self.changes.last().map(|change| change.locations())
  955    }
  956
  957    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  958        self.changes.last().map(|change| change.original.as_slice())
  959    }
  960
  961    pub fn invert_last_group(&mut self) {
  962        if let Some(last) = self.changes.last_mut()
  963            && let Some(current) = last.current.as_mut()
  964        {
  965            mem::swap(&mut last.original, current);
  966        }
  967    }
  968}
  969
  970#[derive(Clone)]
  971struct InlineBlamePopoverState {
  972    scroll_handle: ScrollHandle,
  973    commit_message: Option<ParsedCommitMessage>,
  974    markdown: Entity<Markdown>,
  975}
  976
  977struct InlineBlamePopover {
  978    position: gpui::Point<Pixels>,
  979    hide_task: Option<Task<()>>,
  980    popover_bounds: Option<Bounds<Pixels>>,
  981    popover_state: InlineBlamePopoverState,
  982    keyboard_grace: bool,
  983}
  984
  985enum SelectionDragState {
  986    /// State when no drag related activity is detected.
  987    None,
  988    /// State when the mouse is down on a selection that is about to be dragged.
  989    ReadyToDrag {
  990        selection: Selection<Anchor>,
  991        click_position: gpui::Point<Pixels>,
  992        mouse_down_time: Instant,
  993    },
  994    /// State when the mouse is dragging the selection in the editor.
  995    Dragging {
  996        selection: Selection<Anchor>,
  997        drop_cursor: Selection<Anchor>,
  998        hide_drop_cursor: bool,
  999    },
 1000}
 1001
 1002enum ColumnarSelectionState {
 1003    FromMouse {
 1004        selection_tail: Anchor,
 1005        display_point: Option<DisplayPoint>,
 1006    },
 1007    FromSelection {
 1008        selection_tail: Anchor,
 1009    },
 1010}
 1011
 1012/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1013/// a breakpoint on them.
 1014#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1015struct PhantomBreakpointIndicator {
 1016    display_row: DisplayRow,
 1017    /// There's a small debounce between hovering over the line and showing the indicator.
 1018    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1019    is_active: bool,
 1020    collides_with_existing_breakpoint: bool,
 1021}
 1022
 1023/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1024///
 1025/// See the [module level documentation](self) for more information.
 1026pub struct Editor {
 1027    focus_handle: FocusHandle,
 1028    last_focused_descendant: Option<WeakFocusHandle>,
 1029    /// The text buffer being edited
 1030    buffer: Entity<MultiBuffer>,
 1031    /// Map of how text in the buffer should be displayed.
 1032    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1033    pub display_map: Entity<DisplayMap>,
 1034    placeholder_display_map: Option<Entity<DisplayMap>>,
 1035    pub selections: SelectionsCollection,
 1036    pub scroll_manager: ScrollManager,
 1037    /// When inline assist editors are linked, they all render cursors because
 1038    /// typing enters text into each of them, even the ones that aren't focused.
 1039    pub(crate) show_cursor_when_unfocused: bool,
 1040    columnar_selection_state: Option<ColumnarSelectionState>,
 1041    add_selections_state: Option<AddSelectionsState>,
 1042    select_next_state: Option<SelectNextState>,
 1043    select_prev_state: Option<SelectNextState>,
 1044    selection_history: SelectionHistory,
 1045    defer_selection_effects: bool,
 1046    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1047    autoclose_regions: Vec<AutocloseRegion>,
 1048    snippet_stack: InvalidationStack<SnippetState>,
 1049    select_syntax_node_history: SelectSyntaxNodeHistory,
 1050    ime_transaction: Option<TransactionId>,
 1051    pub diagnostics_max_severity: DiagnosticSeverity,
 1052    active_diagnostics: ActiveDiagnostic,
 1053    show_inline_diagnostics: bool,
 1054    inline_diagnostics_update: Task<()>,
 1055    inline_diagnostics_enabled: bool,
 1056    diagnostics_enabled: bool,
 1057    word_completions_enabled: bool,
 1058    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1059    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1060    hard_wrap: Option<usize>,
 1061    project: Option<Entity<Project>>,
 1062    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1063    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1064    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1065    blink_manager: Entity<BlinkManager>,
 1066    show_cursor_names: bool,
 1067    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1068    pub show_local_selections: bool,
 1069    mode: EditorMode,
 1070    show_breadcrumbs: bool,
 1071    show_gutter: bool,
 1072    show_scrollbars: ScrollbarAxes,
 1073    minimap_visibility: MinimapVisibility,
 1074    offset_content: bool,
 1075    disable_expand_excerpt_buttons: bool,
 1076    show_line_numbers: Option<bool>,
 1077    use_relative_line_numbers: Option<bool>,
 1078    show_git_diff_gutter: Option<bool>,
 1079    show_code_actions: Option<bool>,
 1080    show_runnables: Option<bool>,
 1081    show_breakpoints: Option<bool>,
 1082    show_wrap_guides: Option<bool>,
 1083    show_indent_guides: Option<bool>,
 1084    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1085    highlight_order: usize,
 1086    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1087    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1088    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1089    scrollbar_marker_state: ScrollbarMarkerState,
 1090    active_indent_guides_state: ActiveIndentGuidesState,
 1091    nav_history: Option<ItemNavHistory>,
 1092    context_menu: RefCell<Option<CodeContextMenu>>,
 1093    context_menu_options: Option<ContextMenuOptions>,
 1094    mouse_context_menu: Option<MouseContextMenu>,
 1095    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1096    inline_blame_popover: Option<InlineBlamePopover>,
 1097    inline_blame_popover_show_task: Option<Task<()>>,
 1098    signature_help_state: SignatureHelpState,
 1099    auto_signature_help: Option<bool>,
 1100    find_all_references_task_sources: Vec<Anchor>,
 1101    next_completion_id: CompletionId,
 1102    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1103    code_actions_task: Option<Task<Result<()>>>,
 1104    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1105    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1106    document_highlights_task: Option<Task<()>>,
 1107    linked_editing_range_task: Option<Task<Option<()>>>,
 1108    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1109    pending_rename: Option<RenameState>,
 1110    searchable: bool,
 1111    cursor_shape: CursorShape,
 1112    /// Whether the cursor is offset one character to the left when something is
 1113    /// selected (needed for vim visual mode)
 1114    cursor_offset_on_selection: bool,
 1115    current_line_highlight: Option<CurrentLineHighlight>,
 1116    pub collapse_matches: bool,
 1117    autoindent_mode: Option<AutoindentMode>,
 1118    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1119    input_enabled: bool,
 1120    use_modal_editing: bool,
 1121    read_only: bool,
 1122    leader_id: Option<CollaboratorId>,
 1123    remote_id: Option<ViewId>,
 1124    pub hover_state: HoverState,
 1125    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1126    prev_pressure_stage: Option<PressureStage>,
 1127    gutter_hovered: bool,
 1128    hovered_link_state: Option<HoveredLinkState>,
 1129    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1130    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1131    active_edit_prediction: Option<EditPredictionState>,
 1132    /// Used to prevent flickering as the user types while the menu is open
 1133    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1134    edit_prediction_settings: EditPredictionSettings,
 1135    edit_predictions_hidden_for_vim_mode: bool,
 1136    show_edit_predictions_override: Option<bool>,
 1137    show_completions_on_input_override: Option<bool>,
 1138    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1139    edit_prediction_preview: EditPredictionPreview,
 1140    edit_prediction_indent_conflict: bool,
 1141    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1142    next_inlay_id: usize,
 1143    next_color_inlay_id: usize,
 1144    _subscriptions: Vec<Subscription>,
 1145    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1146    gutter_dimensions: GutterDimensions,
 1147    style: Option<EditorStyle>,
 1148    text_style_refinement: Option<TextStyleRefinement>,
 1149    next_editor_action_id: EditorActionId,
 1150    editor_actions: Rc<
 1151        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1152    >,
 1153    use_autoclose: bool,
 1154    use_auto_surround: bool,
 1155    auto_replace_emoji_shortcode: bool,
 1156    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1157    show_git_blame_gutter: bool,
 1158    show_git_blame_inline: bool,
 1159    show_git_blame_inline_delay_task: Option<Task<()>>,
 1160    git_blame_inline_enabled: bool,
 1161    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1162    buffer_serialization: Option<BufferSerialization>,
 1163    show_selection_menu: Option<bool>,
 1164    blame: Option<Entity<GitBlame>>,
 1165    blame_subscription: Option<Subscription>,
 1166    custom_context_menu: Option<
 1167        Box<
 1168            dyn 'static
 1169                + Fn(
 1170                    &mut Self,
 1171                    DisplayPoint,
 1172                    &mut Window,
 1173                    &mut Context<Self>,
 1174                ) -> Option<Entity<ui::ContextMenu>>,
 1175        >,
 1176    >,
 1177    last_bounds: Option<Bounds<Pixels>>,
 1178    last_position_map: Option<Rc<PositionMap>>,
 1179    expect_bounds_change: Option<Bounds<Pixels>>,
 1180    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1181    tasks_update_task: Option<Task<()>>,
 1182    breakpoint_store: Option<Entity<BreakpointStore>>,
 1183    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1184    hovered_diff_hunk_row: Option<DisplayRow>,
 1185    pull_diagnostics_task: Task<()>,
 1186    pull_diagnostics_background_task: Task<()>,
 1187    in_project_search: bool,
 1188    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1189    breadcrumb_header: Option<String>,
 1190    focused_block: Option<FocusedBlock>,
 1191    next_scroll_position: NextScrollCursorCenterTopBottom,
 1192    addons: HashMap<TypeId, Box<dyn Addon>>,
 1193    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1194    load_diff_task: Option<Shared<Task<()>>>,
 1195    /// Whether we are temporarily displaying a diff other than git's
 1196    temporary_diff_override: bool,
 1197    selection_mark_mode: bool,
 1198    toggle_fold_multiple_buffers: Task<()>,
 1199    _scroll_cursor_center_top_bottom_task: Task<()>,
 1200    serialize_selections: Task<()>,
 1201    serialize_folds: Task<()>,
 1202    mouse_cursor_hidden: bool,
 1203    minimap: Option<Entity<Self>>,
 1204    hide_mouse_mode: HideMouseMode,
 1205    pub change_list: ChangeList,
 1206    inline_value_cache: InlineValueCache,
 1207
 1208    selection_drag_state: SelectionDragState,
 1209    colors: Option<LspColorData>,
 1210    post_scroll_update: Task<()>,
 1211    refresh_colors_task: Task<()>,
 1212    inlay_hints: Option<LspInlayHintData>,
 1213    folding_newlines: Task<()>,
 1214    select_next_is_case_sensitive: Option<bool>,
 1215    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1216    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1217    accent_data: Option<AccentData>,
 1218    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1219    use_base_text_line_numbers: bool,
 1220}
 1221
 1222#[derive(Debug, PartialEq)]
 1223struct AccentData {
 1224    colors: AccentColors,
 1225    overrides: Vec<SharedString>,
 1226}
 1227
 1228fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1229    if debounce_ms > 0 {
 1230        Some(Duration::from_millis(debounce_ms))
 1231    } else {
 1232        None
 1233    }
 1234}
 1235
 1236#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1237enum NextScrollCursorCenterTopBottom {
 1238    #[default]
 1239    Center,
 1240    Top,
 1241    Bottom,
 1242}
 1243
 1244impl NextScrollCursorCenterTopBottom {
 1245    fn next(&self) -> Self {
 1246        match self {
 1247            Self::Center => Self::Top,
 1248            Self::Top => Self::Bottom,
 1249            Self::Bottom => Self::Center,
 1250        }
 1251    }
 1252}
 1253
 1254#[derive(Clone)]
 1255pub struct EditorSnapshot {
 1256    pub mode: EditorMode,
 1257    show_gutter: bool,
 1258    offset_content: bool,
 1259    show_line_numbers: Option<bool>,
 1260    show_git_diff_gutter: Option<bool>,
 1261    show_code_actions: Option<bool>,
 1262    show_runnables: Option<bool>,
 1263    show_breakpoints: Option<bool>,
 1264    git_blame_gutter_max_author_length: Option<usize>,
 1265    pub display_snapshot: DisplaySnapshot,
 1266    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1267    is_focused: bool,
 1268    scroll_anchor: ScrollAnchor,
 1269    ongoing_scroll: OngoingScroll,
 1270    current_line_highlight: CurrentLineHighlight,
 1271    gutter_hovered: bool,
 1272}
 1273
 1274#[derive(Default, Debug, Clone, Copy)]
 1275pub struct GutterDimensions {
 1276    pub left_padding: Pixels,
 1277    pub right_padding: Pixels,
 1278    pub width: Pixels,
 1279    pub margin: Pixels,
 1280    pub git_blame_entries_width: Option<Pixels>,
 1281}
 1282
 1283impl GutterDimensions {
 1284    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1285        Self {
 1286            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1287            ..Default::default()
 1288        }
 1289    }
 1290
 1291    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1292        -cx.text_system().descent(font_id, font_size)
 1293    }
 1294    /// The full width of the space taken up by the gutter.
 1295    pub fn full_width(&self) -> Pixels {
 1296        self.margin + self.width
 1297    }
 1298
 1299    /// The width of the space reserved for the fold indicators,
 1300    /// use alongside 'justify_end' and `gutter_width` to
 1301    /// right align content with the line numbers
 1302    pub fn fold_area_width(&self) -> Pixels {
 1303        self.margin + self.right_padding
 1304    }
 1305}
 1306
 1307struct CharacterDimensions {
 1308    em_width: Pixels,
 1309    em_advance: Pixels,
 1310    line_height: Pixels,
 1311}
 1312
 1313#[derive(Debug)]
 1314pub struct RemoteSelection {
 1315    pub replica_id: ReplicaId,
 1316    pub selection: Selection<Anchor>,
 1317    pub cursor_shape: CursorShape,
 1318    pub collaborator_id: CollaboratorId,
 1319    pub line_mode: bool,
 1320    pub user_name: Option<SharedString>,
 1321    pub color: PlayerColor,
 1322}
 1323
 1324#[derive(Clone, Debug)]
 1325struct SelectionHistoryEntry {
 1326    selections: Arc<[Selection<Anchor>]>,
 1327    select_next_state: Option<SelectNextState>,
 1328    select_prev_state: Option<SelectNextState>,
 1329    add_selections_state: Option<AddSelectionsState>,
 1330}
 1331
 1332#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1333enum SelectionHistoryMode {
 1334    #[default]
 1335    Normal,
 1336    Undoing,
 1337    Redoing,
 1338    Skipping,
 1339}
 1340
 1341#[derive(Clone, PartialEq, Eq, Hash)]
 1342struct HoveredCursor {
 1343    replica_id: ReplicaId,
 1344    selection_id: usize,
 1345}
 1346
 1347#[derive(Debug)]
 1348/// SelectionEffects controls the side-effects of updating the selection.
 1349///
 1350/// The default behaviour does "what you mostly want":
 1351/// - it pushes to the nav history if the cursor moved by >10 lines
 1352/// - it re-triggers completion requests
 1353/// - it scrolls to fit
 1354///
 1355/// You might want to modify these behaviours. For example when doing a "jump"
 1356/// like go to definition, we always want to add to nav history; but when scrolling
 1357/// in vim mode we never do.
 1358///
 1359/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1360/// move.
 1361#[derive(Clone)]
 1362pub struct SelectionEffects {
 1363    nav_history: Option<bool>,
 1364    completions: bool,
 1365    scroll: Option<Autoscroll>,
 1366}
 1367
 1368impl Default for SelectionEffects {
 1369    fn default() -> Self {
 1370        Self {
 1371            nav_history: None,
 1372            completions: true,
 1373            scroll: Some(Autoscroll::fit()),
 1374        }
 1375    }
 1376}
 1377impl SelectionEffects {
 1378    pub fn scroll(scroll: Autoscroll) -> Self {
 1379        Self {
 1380            scroll: Some(scroll),
 1381            ..Default::default()
 1382        }
 1383    }
 1384
 1385    pub fn no_scroll() -> Self {
 1386        Self {
 1387            scroll: None,
 1388            ..Default::default()
 1389        }
 1390    }
 1391
 1392    pub fn completions(self, completions: bool) -> Self {
 1393        Self {
 1394            completions,
 1395            ..self
 1396        }
 1397    }
 1398
 1399    pub fn nav_history(self, nav_history: bool) -> Self {
 1400        Self {
 1401            nav_history: Some(nav_history),
 1402            ..self
 1403        }
 1404    }
 1405}
 1406
 1407struct DeferredSelectionEffectsState {
 1408    changed: bool,
 1409    effects: SelectionEffects,
 1410    old_cursor_position: Anchor,
 1411    history_entry: SelectionHistoryEntry,
 1412}
 1413
 1414#[derive(Default)]
 1415struct SelectionHistory {
 1416    #[allow(clippy::type_complexity)]
 1417    selections_by_transaction:
 1418        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1419    mode: SelectionHistoryMode,
 1420    undo_stack: VecDeque<SelectionHistoryEntry>,
 1421    redo_stack: VecDeque<SelectionHistoryEntry>,
 1422}
 1423
 1424impl SelectionHistory {
 1425    #[track_caller]
 1426    fn insert_transaction(
 1427        &mut self,
 1428        transaction_id: TransactionId,
 1429        selections: Arc<[Selection<Anchor>]>,
 1430    ) {
 1431        if selections.is_empty() {
 1432            log::error!(
 1433                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1434                std::panic::Location::caller()
 1435            );
 1436            return;
 1437        }
 1438        self.selections_by_transaction
 1439            .insert(transaction_id, (selections, None));
 1440    }
 1441
 1442    #[allow(clippy::type_complexity)]
 1443    fn transaction(
 1444        &self,
 1445        transaction_id: TransactionId,
 1446    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1447        self.selections_by_transaction.get(&transaction_id)
 1448    }
 1449
 1450    #[allow(clippy::type_complexity)]
 1451    fn transaction_mut(
 1452        &mut self,
 1453        transaction_id: TransactionId,
 1454    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1455        self.selections_by_transaction.get_mut(&transaction_id)
 1456    }
 1457
 1458    fn push(&mut self, entry: SelectionHistoryEntry) {
 1459        if !entry.selections.is_empty() {
 1460            match self.mode {
 1461                SelectionHistoryMode::Normal => {
 1462                    self.push_undo(entry);
 1463                    self.redo_stack.clear();
 1464                }
 1465                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1466                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1467                SelectionHistoryMode::Skipping => {}
 1468            }
 1469        }
 1470    }
 1471
 1472    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1473        if self
 1474            .undo_stack
 1475            .back()
 1476            .is_none_or(|e| e.selections != entry.selections)
 1477        {
 1478            self.undo_stack.push_back(entry);
 1479            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1480                self.undo_stack.pop_front();
 1481            }
 1482        }
 1483    }
 1484
 1485    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1486        if self
 1487            .redo_stack
 1488            .back()
 1489            .is_none_or(|e| e.selections != entry.selections)
 1490        {
 1491            self.redo_stack.push_back(entry);
 1492            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1493                self.redo_stack.pop_front();
 1494            }
 1495        }
 1496    }
 1497}
 1498
 1499#[derive(Clone, Copy)]
 1500pub struct RowHighlightOptions {
 1501    pub autoscroll: bool,
 1502    pub include_gutter: bool,
 1503}
 1504
 1505impl Default for RowHighlightOptions {
 1506    fn default() -> Self {
 1507        Self {
 1508            autoscroll: Default::default(),
 1509            include_gutter: true,
 1510        }
 1511    }
 1512}
 1513
 1514struct RowHighlight {
 1515    index: usize,
 1516    range: Range<Anchor>,
 1517    color: Hsla,
 1518    options: RowHighlightOptions,
 1519    type_id: TypeId,
 1520}
 1521
 1522#[derive(Clone, Debug)]
 1523struct AddSelectionsState {
 1524    groups: Vec<AddSelectionsGroup>,
 1525}
 1526
 1527#[derive(Clone, Debug)]
 1528struct AddSelectionsGroup {
 1529    above: bool,
 1530    stack: Vec<usize>,
 1531}
 1532
 1533#[derive(Clone)]
 1534struct SelectNextState {
 1535    query: AhoCorasick,
 1536    wordwise: bool,
 1537    done: bool,
 1538}
 1539
 1540impl std::fmt::Debug for SelectNextState {
 1541    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1542        f.debug_struct(std::any::type_name::<Self>())
 1543            .field("wordwise", &self.wordwise)
 1544            .field("done", &self.done)
 1545            .finish()
 1546    }
 1547}
 1548
 1549#[derive(Debug)]
 1550struct AutocloseRegion {
 1551    selection_id: usize,
 1552    range: Range<Anchor>,
 1553    pair: BracketPair,
 1554}
 1555
 1556#[derive(Debug)]
 1557struct SnippetState {
 1558    ranges: Vec<Vec<Range<Anchor>>>,
 1559    active_index: usize,
 1560    choices: Vec<Option<Vec<String>>>,
 1561}
 1562
 1563#[doc(hidden)]
 1564pub struct RenameState {
 1565    pub range: Range<Anchor>,
 1566    pub old_name: Arc<str>,
 1567    pub editor: Entity<Editor>,
 1568    block_id: CustomBlockId,
 1569}
 1570
 1571struct InvalidationStack<T>(Vec<T>);
 1572
 1573struct RegisteredEditPredictionDelegate {
 1574    provider: Arc<dyn EditPredictionDelegateHandle>,
 1575    _subscription: Subscription,
 1576}
 1577
 1578#[derive(Debug, PartialEq, Eq)]
 1579pub struct ActiveDiagnosticGroup {
 1580    pub active_range: Range<Anchor>,
 1581    pub active_message: String,
 1582    pub group_id: usize,
 1583    pub blocks: HashSet<CustomBlockId>,
 1584}
 1585
 1586#[derive(Debug, PartialEq, Eq)]
 1587
 1588pub(crate) enum ActiveDiagnostic {
 1589    None,
 1590    All,
 1591    Group(ActiveDiagnosticGroup),
 1592}
 1593
 1594#[derive(Serialize, Deserialize, Clone, Debug)]
 1595pub struct ClipboardSelection {
 1596    /// The number of bytes in this selection.
 1597    pub len: usize,
 1598    /// Whether this was a full-line selection.
 1599    pub is_entire_line: bool,
 1600    /// The indentation of the first line when this content was originally copied.
 1601    pub first_line_indent: u32,
 1602    #[serde(default)]
 1603    pub file_path: Option<PathBuf>,
 1604    #[serde(default)]
 1605    pub line_range: Option<RangeInclusive<u32>>,
 1606}
 1607
 1608impl ClipboardSelection {
 1609    pub fn for_buffer(
 1610        len: usize,
 1611        is_entire_line: bool,
 1612        range: Range<Point>,
 1613        buffer: &MultiBufferSnapshot,
 1614        project: Option<&Entity<Project>>,
 1615        cx: &App,
 1616    ) -> Self {
 1617        let first_line_indent = buffer
 1618            .indent_size_for_line(MultiBufferRow(range.start.row))
 1619            .len;
 1620
 1621        let file_path = util::maybe!({
 1622            let project = project?.read(cx);
 1623            let file = buffer.file_at(range.start)?;
 1624            let project_path = ProjectPath {
 1625                worktree_id: file.worktree_id(cx),
 1626                path: file.path().clone(),
 1627            };
 1628            project.absolute_path(&project_path, cx)
 1629        });
 1630
 1631        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1632
 1633        Self {
 1634            len,
 1635            is_entire_line,
 1636            first_line_indent,
 1637            file_path,
 1638            line_range,
 1639        }
 1640    }
 1641}
 1642
 1643// selections, scroll behavior, was newest selection reversed
 1644type SelectSyntaxNodeHistoryState = (
 1645    Box<[Selection<MultiBufferOffset>]>,
 1646    SelectSyntaxNodeScrollBehavior,
 1647    bool,
 1648);
 1649
 1650#[derive(Default)]
 1651struct SelectSyntaxNodeHistory {
 1652    stack: Vec<SelectSyntaxNodeHistoryState>,
 1653    // disable temporarily to allow changing selections without losing the stack
 1654    pub disable_clearing: bool,
 1655}
 1656
 1657impl SelectSyntaxNodeHistory {
 1658    pub fn try_clear(&mut self) {
 1659        if !self.disable_clearing {
 1660            self.stack.clear();
 1661        }
 1662    }
 1663
 1664    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1665        self.stack.push(selection);
 1666    }
 1667
 1668    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1669        self.stack.pop()
 1670    }
 1671}
 1672
 1673enum SelectSyntaxNodeScrollBehavior {
 1674    CursorTop,
 1675    FitSelection,
 1676    CursorBottom,
 1677}
 1678
 1679#[derive(Debug)]
 1680pub(crate) struct NavigationData {
 1681    cursor_anchor: Anchor,
 1682    cursor_position: Point,
 1683    scroll_anchor: ScrollAnchor,
 1684    scroll_top_row: u32,
 1685}
 1686
 1687#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1688pub enum GotoDefinitionKind {
 1689    Symbol,
 1690    Declaration,
 1691    Type,
 1692    Implementation,
 1693}
 1694
 1695pub enum FormatTarget {
 1696    Buffers(HashSet<Entity<Buffer>>),
 1697    Ranges(Vec<Range<MultiBufferPoint>>),
 1698}
 1699
 1700pub(crate) struct FocusedBlock {
 1701    id: BlockId,
 1702    focus_handle: WeakFocusHandle,
 1703}
 1704
 1705#[derive(Clone, Debug)]
 1706enum JumpData {
 1707    MultiBufferRow {
 1708        row: MultiBufferRow,
 1709        line_offset_from_top: u32,
 1710    },
 1711    MultiBufferPoint {
 1712        excerpt_id: ExcerptId,
 1713        position: Point,
 1714        anchor: text::Anchor,
 1715        line_offset_from_top: u32,
 1716    },
 1717}
 1718
 1719pub enum MultibufferSelectionMode {
 1720    First,
 1721    All,
 1722}
 1723
 1724#[derive(Clone, Copy, Debug, Default)]
 1725pub struct RewrapOptions {
 1726    pub override_language_settings: bool,
 1727    pub preserve_existing_whitespace: bool,
 1728}
 1729
 1730impl Editor {
 1731    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1732        let buffer = cx.new(|cx| Buffer::local("", cx));
 1733        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1734        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1735    }
 1736
 1737    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1738        let buffer = cx.new(|cx| Buffer::local("", cx));
 1739        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1740        Self::new(EditorMode::full(), buffer, None, window, cx)
 1741    }
 1742
 1743    pub fn auto_height(
 1744        min_lines: usize,
 1745        max_lines: usize,
 1746        window: &mut Window,
 1747        cx: &mut Context<Self>,
 1748    ) -> Self {
 1749        let buffer = cx.new(|cx| Buffer::local("", cx));
 1750        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1751        Self::new(
 1752            EditorMode::AutoHeight {
 1753                min_lines,
 1754                max_lines: Some(max_lines),
 1755            },
 1756            buffer,
 1757            None,
 1758            window,
 1759            cx,
 1760        )
 1761    }
 1762
 1763    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1764    /// The editor grows as tall as needed to fit its content.
 1765    pub fn auto_height_unbounded(
 1766        min_lines: usize,
 1767        window: &mut Window,
 1768        cx: &mut Context<Self>,
 1769    ) -> Self {
 1770        let buffer = cx.new(|cx| Buffer::local("", cx));
 1771        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1772        Self::new(
 1773            EditorMode::AutoHeight {
 1774                min_lines,
 1775                max_lines: None,
 1776            },
 1777            buffer,
 1778            None,
 1779            window,
 1780            cx,
 1781        )
 1782    }
 1783
 1784    pub fn for_buffer(
 1785        buffer: Entity<Buffer>,
 1786        project: Option<Entity<Project>>,
 1787        window: &mut Window,
 1788        cx: &mut Context<Self>,
 1789    ) -> Self {
 1790        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1791        Self::new(EditorMode::full(), buffer, project, window, cx)
 1792    }
 1793
 1794    pub fn for_multibuffer(
 1795        buffer: Entity<MultiBuffer>,
 1796        project: Option<Entity<Project>>,
 1797        window: &mut Window,
 1798        cx: &mut Context<Self>,
 1799    ) -> Self {
 1800        Self::new(EditorMode::full(), buffer, project, window, cx)
 1801    }
 1802
 1803    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1804        let mut clone = Self::new(
 1805            self.mode.clone(),
 1806            self.buffer.clone(),
 1807            self.project.clone(),
 1808            window,
 1809            cx,
 1810        );
 1811        self.display_map.update(cx, |display_map, cx| {
 1812            let snapshot = display_map.snapshot(cx);
 1813            clone.display_map.update(cx, |display_map, cx| {
 1814                display_map.set_state(&snapshot, cx);
 1815            });
 1816        });
 1817        clone.folds_did_change(cx);
 1818        clone.selections.clone_state(&self.selections);
 1819        clone.scroll_manager.clone_state(&self.scroll_manager);
 1820        clone.searchable = self.searchable;
 1821        clone.read_only = self.read_only;
 1822        clone
 1823    }
 1824
 1825    pub fn new(
 1826        mode: EditorMode,
 1827        buffer: Entity<MultiBuffer>,
 1828        project: Option<Entity<Project>>,
 1829        window: &mut Window,
 1830        cx: &mut Context<Self>,
 1831    ) -> Self {
 1832        Editor::new_internal(mode, buffer, project, None, window, cx)
 1833    }
 1834
 1835    pub fn sticky_headers(
 1836        &self,
 1837        style: &EditorStyle,
 1838        cx: &App,
 1839    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1840        let multi_buffer = self.buffer().read(cx);
 1841        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1842        let multi_buffer_visible_start = self
 1843            .scroll_manager
 1844            .anchor()
 1845            .anchor
 1846            .to_point(&multi_buffer_snapshot);
 1847        let max_row = multi_buffer_snapshot.max_point().row;
 1848
 1849        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1850        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1851
 1852        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1853            let outline_items = buffer
 1854                .outline_items_containing(
 1855                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1856                    true,
 1857                    Some(style.syntax.as_ref()),
 1858                )
 1859                .into_iter()
 1860                .map(|outline_item| OutlineItem {
 1861                    depth: outline_item.depth,
 1862                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1863                    source_range_for_text: Anchor::range_in_buffer(
 1864                        *excerpt_id,
 1865                        outline_item.source_range_for_text,
 1866                    ),
 1867                    text: outline_item.text,
 1868                    highlight_ranges: outline_item.highlight_ranges,
 1869                    name_ranges: outline_item.name_ranges,
 1870                    body_range: outline_item
 1871                        .body_range
 1872                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1873                    annotation_range: outline_item
 1874                        .annotation_range
 1875                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1876                });
 1877            return Some(outline_items.collect());
 1878        }
 1879
 1880        None
 1881    }
 1882
 1883    fn new_internal(
 1884        mode: EditorMode,
 1885        multi_buffer: Entity<MultiBuffer>,
 1886        project: Option<Entity<Project>>,
 1887        display_map: Option<Entity<DisplayMap>>,
 1888        window: &mut Window,
 1889        cx: &mut Context<Self>,
 1890    ) -> Self {
 1891        debug_assert!(
 1892            display_map.is_none() || mode.is_minimap(),
 1893            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1894        );
 1895
 1896        let full_mode = mode.is_full();
 1897        let is_minimap = mode.is_minimap();
 1898        let diagnostics_max_severity = if full_mode {
 1899            EditorSettings::get_global(cx)
 1900                .diagnostics_max_severity
 1901                .unwrap_or(DiagnosticSeverity::Hint)
 1902        } else {
 1903            DiagnosticSeverity::Off
 1904        };
 1905        let style = window.text_style();
 1906        let font_size = style.font_size.to_pixels(window.rem_size());
 1907        let editor = cx.entity().downgrade();
 1908        let fold_placeholder = FoldPlaceholder {
 1909            constrain_width: false,
 1910            render: Arc::new(move |fold_id, fold_range, cx| {
 1911                let editor = editor.clone();
 1912                div()
 1913                    .id(fold_id)
 1914                    .bg(cx.theme().colors().ghost_element_background)
 1915                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1916                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1917                    .rounded_xs()
 1918                    .size_full()
 1919                    .cursor_pointer()
 1920                    .child("")
 1921                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1922                    .on_click(move |_, _window, cx| {
 1923                        editor
 1924                            .update(cx, |editor, cx| {
 1925                                editor.unfold_ranges(
 1926                                    &[fold_range.start..fold_range.end],
 1927                                    true,
 1928                                    false,
 1929                                    cx,
 1930                                );
 1931                                cx.stop_propagation();
 1932                            })
 1933                            .ok();
 1934                    })
 1935                    .into_any()
 1936            }),
 1937            merge_adjacent: true,
 1938            ..FoldPlaceholder::default()
 1939        };
 1940        let display_map = display_map.unwrap_or_else(|| {
 1941            cx.new(|cx| {
 1942                DisplayMap::new(
 1943                    multi_buffer.clone(),
 1944                    style.font(),
 1945                    font_size,
 1946                    None,
 1947                    FILE_HEADER_HEIGHT,
 1948                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1949                    fold_placeholder,
 1950                    diagnostics_max_severity,
 1951                    cx,
 1952                )
 1953            })
 1954        });
 1955
 1956        let selections = SelectionsCollection::new();
 1957
 1958        let blink_manager = cx.new(|cx| {
 1959            let mut blink_manager = BlinkManager::new(
 1960                CURSOR_BLINK_INTERVAL,
 1961                |cx| EditorSettings::get_global(cx).cursor_blink,
 1962                cx,
 1963            );
 1964            if is_minimap {
 1965                blink_manager.disable(cx);
 1966            }
 1967            blink_manager
 1968        });
 1969
 1970        let soft_wrap_mode_override =
 1971            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1972
 1973        let mut project_subscriptions = Vec::new();
 1974        if full_mode && let Some(project) = project.as_ref() {
 1975            project_subscriptions.push(cx.subscribe_in(
 1976                project,
 1977                window,
 1978                |editor, _, event, window, cx| match event {
 1979                    project::Event::RefreshCodeLens => {
 1980                        // we always query lens with actions, without storing them, always refreshing them
 1981                    }
 1982                    project::Event::RefreshInlayHints {
 1983                        server_id,
 1984                        request_id,
 1985                    } => {
 1986                        editor.refresh_inlay_hints(
 1987                            InlayHintRefreshReason::RefreshRequested {
 1988                                server_id: *server_id,
 1989                                request_id: *request_id,
 1990                            },
 1991                            cx,
 1992                        );
 1993                    }
 1994                    project::Event::LanguageServerRemoved(..) => {
 1995                        if editor.tasks_update_task.is_none() {
 1996                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1997                        }
 1998                        editor.registered_buffers.clear();
 1999                        editor.register_visible_buffers(cx);
 2000                    }
 2001                    project::Event::LanguageServerAdded(..) => {
 2002                        if editor.tasks_update_task.is_none() {
 2003                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2004                        }
 2005                    }
 2006                    project::Event::SnippetEdit(id, snippet_edits) => {
 2007                        // todo(lw): Non singletons
 2008                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2009                            let snapshot = buffer.read(cx).snapshot();
 2010                            let focus_handle = editor.focus_handle(cx);
 2011                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2012                                for (range, snippet) in snippet_edits {
 2013                                    let buffer_range =
 2014                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2015                                    editor
 2016                                        .insert_snippet(
 2017                                            &[MultiBufferOffset(buffer_range.start)
 2018                                                ..MultiBufferOffset(buffer_range.end)],
 2019                                            snippet.clone(),
 2020                                            window,
 2021                                            cx,
 2022                                        )
 2023                                        .ok();
 2024                                }
 2025                            }
 2026                        }
 2027                    }
 2028                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2029                        let buffer_id = *buffer_id;
 2030                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2031                            editor.register_buffer(buffer_id, cx);
 2032                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2033                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2034                            refresh_linked_ranges(editor, window, cx);
 2035                            editor.refresh_code_actions(window, cx);
 2036                            editor.refresh_document_highlights(cx);
 2037                        }
 2038                    }
 2039
 2040                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2041                        let Some(workspace) = editor.workspace() else {
 2042                            return;
 2043                        };
 2044                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2045                        else {
 2046                            return;
 2047                        };
 2048
 2049                        if active_editor.entity_id() == cx.entity_id() {
 2050                            let entity_id = cx.entity_id();
 2051                            workspace.update(cx, |this, cx| {
 2052                                this.panes_mut()
 2053                                    .iter_mut()
 2054                                    .filter(|pane| pane.entity_id() != entity_id)
 2055                                    .for_each(|p| {
 2056                                        p.update(cx, |pane, _| {
 2057                                            pane.nav_history_mut().rename_item(
 2058                                                entity_id,
 2059                                                project_path.clone(),
 2060                                                abs_path.clone().into(),
 2061                                            );
 2062                                        })
 2063                                    });
 2064                            });
 2065
 2066                            Self::open_transaction_for_hidden_buffers(
 2067                                workspace,
 2068                                transaction.clone(),
 2069                                "Rename".to_string(),
 2070                                window,
 2071                                cx,
 2072                            );
 2073                        }
 2074                    }
 2075
 2076                    project::Event::WorkspaceEditApplied(transaction) => {
 2077                        let Some(workspace) = editor.workspace() else {
 2078                            return;
 2079                        };
 2080                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2081                        else {
 2082                            return;
 2083                        };
 2084
 2085                        if active_editor.entity_id() == cx.entity_id() {
 2086                            Self::open_transaction_for_hidden_buffers(
 2087                                workspace,
 2088                                transaction.clone(),
 2089                                "LSP Edit".to_string(),
 2090                                window,
 2091                                cx,
 2092                            );
 2093                        }
 2094                    }
 2095
 2096                    _ => {}
 2097                },
 2098            ));
 2099            if let Some(task_inventory) = project
 2100                .read(cx)
 2101                .task_store()
 2102                .read(cx)
 2103                .task_inventory()
 2104                .cloned()
 2105            {
 2106                project_subscriptions.push(cx.observe_in(
 2107                    &task_inventory,
 2108                    window,
 2109                    |editor, _, window, cx| {
 2110                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2111                    },
 2112                ));
 2113            };
 2114
 2115            project_subscriptions.push(cx.subscribe_in(
 2116                &project.read(cx).breakpoint_store(),
 2117                window,
 2118                |editor, _, event, window, cx| match event {
 2119                    BreakpointStoreEvent::ClearDebugLines => {
 2120                        editor.clear_row_highlights::<ActiveDebugLine>();
 2121                        editor.refresh_inline_values(cx);
 2122                    }
 2123                    BreakpointStoreEvent::SetDebugLine => {
 2124                        if editor.go_to_active_debug_line(window, cx) {
 2125                            cx.stop_propagation();
 2126                        }
 2127
 2128                        editor.refresh_inline_values(cx);
 2129                    }
 2130                    _ => {}
 2131                },
 2132            ));
 2133            let git_store = project.read(cx).git_store().clone();
 2134            let project = project.clone();
 2135            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2136                if let GitStoreEvent::RepositoryAdded = event {
 2137                    this.load_diff_task = Some(
 2138                        update_uncommitted_diff_for_buffer(
 2139                            cx.entity(),
 2140                            &project,
 2141                            this.buffer.read(cx).all_buffers(),
 2142                            this.buffer.clone(),
 2143                            cx,
 2144                        )
 2145                        .shared(),
 2146                    );
 2147                }
 2148            }));
 2149        }
 2150
 2151        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2152
 2153        let inlay_hint_settings =
 2154            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2155        let focus_handle = cx.focus_handle();
 2156        if !is_minimap {
 2157            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2158                .detach();
 2159            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2160                .detach();
 2161            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2162                .detach();
 2163            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2164                .detach();
 2165            cx.observe_pending_input(window, Self::observe_pending_input)
 2166                .detach();
 2167        }
 2168
 2169        let show_indent_guides =
 2170            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2171                Some(false)
 2172            } else {
 2173                None
 2174            };
 2175
 2176        let breakpoint_store = match (&mode, project.as_ref()) {
 2177            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2178            _ => None,
 2179        };
 2180
 2181        let mut code_action_providers = Vec::new();
 2182        let mut load_uncommitted_diff = None;
 2183        if let Some(project) = project.clone() {
 2184            load_uncommitted_diff = Some(
 2185                update_uncommitted_diff_for_buffer(
 2186                    cx.entity(),
 2187                    &project,
 2188                    multi_buffer.read(cx).all_buffers(),
 2189                    multi_buffer.clone(),
 2190                    cx,
 2191                )
 2192                .shared(),
 2193            );
 2194            code_action_providers.push(Rc::new(project) as Rc<_>);
 2195        }
 2196
 2197        let mut editor = Self {
 2198            focus_handle,
 2199            show_cursor_when_unfocused: false,
 2200            last_focused_descendant: None,
 2201            buffer: multi_buffer.clone(),
 2202            display_map: display_map.clone(),
 2203            placeholder_display_map: None,
 2204            selections,
 2205            scroll_manager: ScrollManager::new(cx),
 2206            columnar_selection_state: None,
 2207            add_selections_state: None,
 2208            select_next_state: None,
 2209            select_prev_state: None,
 2210            selection_history: SelectionHistory::default(),
 2211            defer_selection_effects: false,
 2212            deferred_selection_effects_state: None,
 2213            autoclose_regions: Vec::new(),
 2214            snippet_stack: InvalidationStack::default(),
 2215            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2216            ime_transaction: None,
 2217            active_diagnostics: ActiveDiagnostic::None,
 2218            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2219            inline_diagnostics_update: Task::ready(()),
 2220            inline_diagnostics: Vec::new(),
 2221            soft_wrap_mode_override,
 2222            diagnostics_max_severity,
 2223            hard_wrap: None,
 2224            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2225            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2226            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2227            project,
 2228            blink_manager: blink_manager.clone(),
 2229            show_local_selections: true,
 2230            show_scrollbars: ScrollbarAxes {
 2231                horizontal: full_mode,
 2232                vertical: full_mode,
 2233            },
 2234            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2235            offset_content: !matches!(mode, EditorMode::SingleLine),
 2236            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2237            show_gutter: full_mode,
 2238            show_line_numbers: (!full_mode).then_some(false),
 2239            use_relative_line_numbers: None,
 2240            disable_expand_excerpt_buttons: !full_mode,
 2241            show_git_diff_gutter: None,
 2242            show_code_actions: None,
 2243            show_runnables: None,
 2244            show_breakpoints: None,
 2245            show_wrap_guides: None,
 2246            show_indent_guides,
 2247            buffers_with_disabled_indent_guides: HashSet::default(),
 2248            highlight_order: 0,
 2249            highlighted_rows: HashMap::default(),
 2250            background_highlights: HashMap::default(),
 2251            gutter_highlights: HashMap::default(),
 2252            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2253            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2254            nav_history: None,
 2255            context_menu: RefCell::new(None),
 2256            context_menu_options: None,
 2257            mouse_context_menu: None,
 2258            completion_tasks: Vec::new(),
 2259            inline_blame_popover: None,
 2260            inline_blame_popover_show_task: None,
 2261            signature_help_state: SignatureHelpState::default(),
 2262            auto_signature_help: None,
 2263            find_all_references_task_sources: Vec::new(),
 2264            next_completion_id: 0,
 2265            next_inlay_id: 0,
 2266            code_action_providers,
 2267            available_code_actions: None,
 2268            code_actions_task: None,
 2269            quick_selection_highlight_task: None,
 2270            debounced_selection_highlight_task: None,
 2271            document_highlights_task: None,
 2272            linked_editing_range_task: None,
 2273            pending_rename: None,
 2274            searchable: !is_minimap,
 2275            cursor_shape: EditorSettings::get_global(cx)
 2276                .cursor_shape
 2277                .unwrap_or_default(),
 2278            cursor_offset_on_selection: false,
 2279            current_line_highlight: None,
 2280            autoindent_mode: Some(AutoindentMode::EachLine),
 2281            collapse_matches: false,
 2282            workspace: None,
 2283            input_enabled: !is_minimap,
 2284            use_modal_editing: full_mode,
 2285            read_only: is_minimap,
 2286            use_autoclose: true,
 2287            use_auto_surround: true,
 2288            auto_replace_emoji_shortcode: false,
 2289            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2290            leader_id: None,
 2291            remote_id: None,
 2292            hover_state: HoverState::default(),
 2293            pending_mouse_down: None,
 2294            prev_pressure_stage: None,
 2295            hovered_link_state: None,
 2296            edit_prediction_provider: None,
 2297            active_edit_prediction: None,
 2298            stale_edit_prediction_in_menu: None,
 2299            edit_prediction_preview: EditPredictionPreview::Inactive {
 2300                released_too_fast: false,
 2301            },
 2302            inline_diagnostics_enabled: full_mode,
 2303            diagnostics_enabled: full_mode,
 2304            word_completions_enabled: full_mode,
 2305            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2306            gutter_hovered: false,
 2307            pixel_position_of_newest_cursor: None,
 2308            last_bounds: None,
 2309            last_position_map: None,
 2310            expect_bounds_change: None,
 2311            gutter_dimensions: GutterDimensions::default(),
 2312            style: None,
 2313            show_cursor_names: false,
 2314            hovered_cursors: HashMap::default(),
 2315            next_editor_action_id: EditorActionId::default(),
 2316            editor_actions: Rc::default(),
 2317            edit_predictions_hidden_for_vim_mode: false,
 2318            show_edit_predictions_override: None,
 2319            show_completions_on_input_override: None,
 2320            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2321            edit_prediction_settings: EditPredictionSettings::Disabled,
 2322            edit_prediction_indent_conflict: false,
 2323            edit_prediction_requires_modifier_in_indent_conflict: true,
 2324            custom_context_menu: None,
 2325            show_git_blame_gutter: false,
 2326            show_git_blame_inline: false,
 2327            show_selection_menu: None,
 2328            show_git_blame_inline_delay_task: None,
 2329            git_blame_inline_enabled: full_mode
 2330                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2331            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2332            buffer_serialization: is_minimap.not().then(|| {
 2333                BufferSerialization::new(
 2334                    ProjectSettings::get_global(cx)
 2335                        .session
 2336                        .restore_unsaved_buffers,
 2337                )
 2338            }),
 2339            blame: None,
 2340            blame_subscription: None,
 2341            tasks: BTreeMap::default(),
 2342
 2343            breakpoint_store,
 2344            gutter_breakpoint_indicator: (None, None),
 2345            hovered_diff_hunk_row: None,
 2346            _subscriptions: (!is_minimap)
 2347                .then(|| {
 2348                    vec![
 2349                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2350                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2351                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2352                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2353                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2354                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2355                        cx.observe_window_activation(window, |editor, window, cx| {
 2356                            let active = window.is_window_active();
 2357                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2358                                if active {
 2359                                    blink_manager.enable(cx);
 2360                                } else {
 2361                                    blink_manager.disable(cx);
 2362                                }
 2363                            });
 2364                            if active {
 2365                                editor.show_mouse_cursor(cx);
 2366                            }
 2367                        }),
 2368                    ]
 2369                })
 2370                .unwrap_or_default(),
 2371            tasks_update_task: None,
 2372            pull_diagnostics_task: Task::ready(()),
 2373            pull_diagnostics_background_task: Task::ready(()),
 2374            colors: None,
 2375            refresh_colors_task: Task::ready(()),
 2376            inlay_hints: None,
 2377            next_color_inlay_id: 0,
 2378            post_scroll_update: Task::ready(()),
 2379            linked_edit_ranges: Default::default(),
 2380            in_project_search: false,
 2381            previous_search_ranges: None,
 2382            breadcrumb_header: None,
 2383            focused_block: None,
 2384            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2385            addons: HashMap::default(),
 2386            registered_buffers: HashMap::default(),
 2387            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2388            selection_mark_mode: false,
 2389            toggle_fold_multiple_buffers: Task::ready(()),
 2390            serialize_selections: Task::ready(()),
 2391            serialize_folds: Task::ready(()),
 2392            text_style_refinement: None,
 2393            load_diff_task: load_uncommitted_diff,
 2394            temporary_diff_override: false,
 2395            mouse_cursor_hidden: false,
 2396            minimap: None,
 2397            hide_mouse_mode: EditorSettings::get_global(cx)
 2398                .hide_mouse
 2399                .unwrap_or_default(),
 2400            change_list: ChangeList::new(),
 2401            mode,
 2402            selection_drag_state: SelectionDragState::None,
 2403            folding_newlines: Task::ready(()),
 2404            lookup_key: None,
 2405            select_next_is_case_sensitive: None,
 2406            applicable_language_settings: HashMap::default(),
 2407            accent_data: None,
 2408            fetched_tree_sitter_chunks: HashMap::default(),
 2409            use_base_text_line_numbers: false,
 2410        };
 2411
 2412        if is_minimap {
 2413            return editor;
 2414        }
 2415
 2416        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2417        editor.accent_data = editor.fetch_accent_data(cx);
 2418
 2419        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2420            editor
 2421                ._subscriptions
 2422                .push(cx.observe(breakpoints, |_, _, cx| {
 2423                    cx.notify();
 2424                }));
 2425        }
 2426        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2427        editor._subscriptions.extend(project_subscriptions);
 2428
 2429        editor._subscriptions.push(cx.subscribe_in(
 2430            &cx.entity(),
 2431            window,
 2432            |editor, _, e: &EditorEvent, window, cx| match e {
 2433                EditorEvent::ScrollPositionChanged { local, .. } => {
 2434                    if *local {
 2435                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2436                        editor.inline_blame_popover.take();
 2437                        let new_anchor = editor.scroll_manager.anchor();
 2438                        let snapshot = editor.snapshot(window, cx);
 2439                        editor.update_restoration_data(cx, move |data| {
 2440                            data.scroll_position = (
 2441                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2442                                new_anchor.offset,
 2443                            );
 2444                        });
 2445
 2446                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2447                            cx.background_executor()
 2448                                .timer(Duration::from_millis(50))
 2449                                .await;
 2450                            editor
 2451                                .update_in(cx, |editor, window, cx| {
 2452                                    editor.register_visible_buffers(cx);
 2453                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2454                                    editor.refresh_inlay_hints(
 2455                                        InlayHintRefreshReason::NewLinesShown,
 2456                                        cx,
 2457                                    );
 2458                                    editor.colorize_brackets(false, cx);
 2459                                })
 2460                                .ok();
 2461                        });
 2462                    }
 2463                }
 2464                EditorEvent::Edited { .. } => {
 2465                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2466                        .map(|vim_mode| vim_mode.0)
 2467                        .unwrap_or(false);
 2468                    if !vim_mode {
 2469                        let display_map = editor.display_snapshot(cx);
 2470                        let selections = editor.selections.all_adjusted_display(&display_map);
 2471                        let pop_state = editor
 2472                            .change_list
 2473                            .last()
 2474                            .map(|previous| {
 2475                                previous.len() == selections.len()
 2476                                    && previous.iter().enumerate().all(|(ix, p)| {
 2477                                        p.to_display_point(&display_map).row()
 2478                                            == selections[ix].head().row()
 2479                                    })
 2480                            })
 2481                            .unwrap_or(false);
 2482                        let new_positions = selections
 2483                            .into_iter()
 2484                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2485                            .collect();
 2486                        editor
 2487                            .change_list
 2488                            .push_to_change_list(pop_state, new_positions);
 2489                    }
 2490                }
 2491                _ => (),
 2492            },
 2493        ));
 2494
 2495        if let Some(dap_store) = editor
 2496            .project
 2497            .as_ref()
 2498            .map(|project| project.read(cx).dap_store())
 2499        {
 2500            let weak_editor = cx.weak_entity();
 2501
 2502            editor
 2503                ._subscriptions
 2504                .push(
 2505                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2506                        let session_entity = cx.entity();
 2507                        weak_editor
 2508                            .update(cx, |editor, cx| {
 2509                                editor._subscriptions.push(
 2510                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2511                                );
 2512                            })
 2513                            .ok();
 2514                    }),
 2515                );
 2516
 2517            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2518                editor
 2519                    ._subscriptions
 2520                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2521            }
 2522        }
 2523
 2524        // skip adding the initial selection to selection history
 2525        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2526        editor.end_selection(window, cx);
 2527        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2528
 2529        editor.scroll_manager.show_scrollbars(window, cx);
 2530        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2531
 2532        if full_mode {
 2533            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2534            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2535
 2536            if editor.git_blame_inline_enabled {
 2537                editor.start_git_blame_inline(false, window, cx);
 2538            }
 2539
 2540            editor.go_to_active_debug_line(window, cx);
 2541
 2542            editor.minimap =
 2543                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2544            editor.colors = Some(LspColorData::new(cx));
 2545            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2546
 2547            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2548                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2549            }
 2550            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2551        }
 2552
 2553        editor
 2554    }
 2555
 2556    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2557        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2558    }
 2559
 2560    pub fn deploy_mouse_context_menu(
 2561        &mut self,
 2562        position: gpui::Point<Pixels>,
 2563        context_menu: Entity<ContextMenu>,
 2564        window: &mut Window,
 2565        cx: &mut Context<Self>,
 2566    ) {
 2567        self.mouse_context_menu = Some(MouseContextMenu::new(
 2568            self,
 2569            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2570            context_menu,
 2571            window,
 2572            cx,
 2573        ));
 2574    }
 2575
 2576    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2577        self.mouse_context_menu
 2578            .as_ref()
 2579            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2580    }
 2581
 2582    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2583        if self
 2584            .selections
 2585            .pending_anchor()
 2586            .is_some_and(|pending_selection| {
 2587                let snapshot = self.buffer().read(cx).snapshot(cx);
 2588                pending_selection.range().includes(range, &snapshot)
 2589            })
 2590        {
 2591            return true;
 2592        }
 2593
 2594        self.selections
 2595            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2596            .into_iter()
 2597            .any(|selection| {
 2598                // This is needed to cover a corner case, if we just check for an existing
 2599                // selection in the fold range, having a cursor at the start of the fold
 2600                // marks it as selected. Non-empty selections don't cause this.
 2601                let length = selection.end - selection.start;
 2602                length > 0
 2603            })
 2604    }
 2605
 2606    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2607        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2608    }
 2609
 2610    fn key_context_internal(
 2611        &self,
 2612        has_active_edit_prediction: bool,
 2613        window: &mut Window,
 2614        cx: &mut App,
 2615    ) -> KeyContext {
 2616        let mut key_context = KeyContext::new_with_defaults();
 2617        key_context.add("Editor");
 2618        let mode = match self.mode {
 2619            EditorMode::SingleLine => "single_line",
 2620            EditorMode::AutoHeight { .. } => "auto_height",
 2621            EditorMode::Minimap { .. } => "minimap",
 2622            EditorMode::Full { .. } => "full",
 2623        };
 2624
 2625        if EditorSettings::jupyter_enabled(cx) {
 2626            key_context.add("jupyter");
 2627        }
 2628
 2629        key_context.set("mode", mode);
 2630        if self.pending_rename.is_some() {
 2631            key_context.add("renaming");
 2632        }
 2633
 2634        if let Some(snippet_stack) = self.snippet_stack.last() {
 2635            key_context.add("in_snippet");
 2636
 2637            if snippet_stack.active_index > 0 {
 2638                key_context.add("has_previous_tabstop");
 2639            }
 2640
 2641            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2642                key_context.add("has_next_tabstop");
 2643            }
 2644        }
 2645
 2646        match self.context_menu.borrow().as_ref() {
 2647            Some(CodeContextMenu::Completions(menu)) => {
 2648                if menu.visible() {
 2649                    key_context.add("menu");
 2650                    key_context.add("showing_completions");
 2651                }
 2652            }
 2653            Some(CodeContextMenu::CodeActions(menu)) => {
 2654                if menu.visible() {
 2655                    key_context.add("menu");
 2656                    key_context.add("showing_code_actions")
 2657                }
 2658            }
 2659            None => {}
 2660        }
 2661
 2662        if self.signature_help_state.has_multiple_signatures() {
 2663            key_context.add("showing_signature_help");
 2664        }
 2665
 2666        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2667        if !self.focus_handle(cx).contains_focused(window, cx)
 2668            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2669        {
 2670            for addon in self.addons.values() {
 2671                addon.extend_key_context(&mut key_context, cx)
 2672            }
 2673        }
 2674
 2675        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2676            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2677                Some(
 2678                    file.full_path(cx)
 2679                        .extension()?
 2680                        .to_string_lossy()
 2681                        .into_owned(),
 2682                )
 2683            }) {
 2684                key_context.set("extension", extension);
 2685            }
 2686        } else {
 2687            key_context.add("multibuffer");
 2688        }
 2689
 2690        if has_active_edit_prediction {
 2691            if self.edit_prediction_in_conflict() {
 2692                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2693            } else {
 2694                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2695                key_context.add("copilot_suggestion");
 2696            }
 2697        }
 2698
 2699        if self.selection_mark_mode {
 2700            key_context.add("selection_mode");
 2701        }
 2702
 2703        let disjoint = self.selections.disjoint_anchors();
 2704        let snapshot = self.snapshot(window, cx);
 2705        let snapshot = snapshot.buffer_snapshot();
 2706        if self.mode == EditorMode::SingleLine
 2707            && let [selection] = disjoint
 2708            && selection.start == selection.end
 2709            && selection.end.to_offset(snapshot) == snapshot.len()
 2710        {
 2711            key_context.add("end_of_input");
 2712        }
 2713
 2714        if self.has_any_expanded_diff_hunks(cx) {
 2715            key_context.add("diffs_expanded");
 2716        }
 2717
 2718        key_context
 2719    }
 2720
 2721    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2722        self.last_bounds.as_ref()
 2723    }
 2724
 2725    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2726        if self.mouse_cursor_hidden {
 2727            self.mouse_cursor_hidden = false;
 2728            cx.notify();
 2729        }
 2730    }
 2731
 2732    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2733        let hide_mouse_cursor = match origin {
 2734            HideMouseCursorOrigin::TypingAction => {
 2735                matches!(
 2736                    self.hide_mouse_mode,
 2737                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2738                )
 2739            }
 2740            HideMouseCursorOrigin::MovementAction => {
 2741                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2742            }
 2743        };
 2744        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2745            self.mouse_cursor_hidden = hide_mouse_cursor;
 2746            cx.notify();
 2747        }
 2748    }
 2749
 2750    pub fn edit_prediction_in_conflict(&self) -> bool {
 2751        if !self.show_edit_predictions_in_menu() {
 2752            return false;
 2753        }
 2754
 2755        let showing_completions = self
 2756            .context_menu
 2757            .borrow()
 2758            .as_ref()
 2759            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2760
 2761        showing_completions
 2762            || self.edit_prediction_requires_modifier()
 2763            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2764            // bindings to insert tab characters.
 2765            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2766    }
 2767
 2768    pub fn accept_edit_prediction_keybind(
 2769        &self,
 2770        granularity: EditPredictionGranularity,
 2771        window: &mut Window,
 2772        cx: &mut App,
 2773    ) -> AcceptEditPredictionBinding {
 2774        let key_context = self.key_context_internal(true, window, cx);
 2775        let in_conflict = self.edit_prediction_in_conflict();
 2776
 2777        let bindings =
 2778            match granularity {
 2779                EditPredictionGranularity::Word => window
 2780                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2781                EditPredictionGranularity::Line => window
 2782                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2783                EditPredictionGranularity::Full => {
 2784                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2785                }
 2786            };
 2787
 2788        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2789            !in_conflict
 2790                || binding
 2791                    .keystrokes()
 2792                    .first()
 2793                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2794        }))
 2795    }
 2796
 2797    pub fn new_file(
 2798        workspace: &mut Workspace,
 2799        _: &workspace::NewFile,
 2800        window: &mut Window,
 2801        cx: &mut Context<Workspace>,
 2802    ) {
 2803        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2804            "Failed to create buffer",
 2805            window,
 2806            cx,
 2807            |e, _, _| match e.error_code() {
 2808                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2809                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2810                e.error_tag("required").unwrap_or("the latest version")
 2811            )),
 2812                _ => None,
 2813            },
 2814        );
 2815    }
 2816
 2817    pub fn new_in_workspace(
 2818        workspace: &mut Workspace,
 2819        window: &mut Window,
 2820        cx: &mut Context<Workspace>,
 2821    ) -> Task<Result<Entity<Editor>>> {
 2822        let project = workspace.project().clone();
 2823        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2824
 2825        cx.spawn_in(window, async move |workspace, cx| {
 2826            let buffer = create.await?;
 2827            workspace.update_in(cx, |workspace, window, cx| {
 2828                let editor =
 2829                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2830                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2831                editor
 2832            })
 2833        })
 2834    }
 2835
 2836    fn new_file_vertical(
 2837        workspace: &mut Workspace,
 2838        _: &workspace::NewFileSplitVertical,
 2839        window: &mut Window,
 2840        cx: &mut Context<Workspace>,
 2841    ) {
 2842        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2843    }
 2844
 2845    fn new_file_horizontal(
 2846        workspace: &mut Workspace,
 2847        _: &workspace::NewFileSplitHorizontal,
 2848        window: &mut Window,
 2849        cx: &mut Context<Workspace>,
 2850    ) {
 2851        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2852    }
 2853
 2854    fn new_file_split(
 2855        workspace: &mut Workspace,
 2856        action: &workspace::NewFileSplit,
 2857        window: &mut Window,
 2858        cx: &mut Context<Workspace>,
 2859    ) {
 2860        Self::new_file_in_direction(workspace, action.0, window, cx)
 2861    }
 2862
 2863    fn new_file_in_direction(
 2864        workspace: &mut Workspace,
 2865        direction: SplitDirection,
 2866        window: &mut Window,
 2867        cx: &mut Context<Workspace>,
 2868    ) {
 2869        let project = workspace.project().clone();
 2870        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2871
 2872        cx.spawn_in(window, async move |workspace, cx| {
 2873            let buffer = create.await?;
 2874            workspace.update_in(cx, move |workspace, window, cx| {
 2875                workspace.split_item(
 2876                    direction,
 2877                    Box::new(
 2878                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2879                    ),
 2880                    window,
 2881                    cx,
 2882                )
 2883            })?;
 2884            anyhow::Ok(())
 2885        })
 2886        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2887            match e.error_code() {
 2888                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2889                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2890                e.error_tag("required").unwrap_or("the latest version")
 2891            )),
 2892                _ => None,
 2893            }
 2894        });
 2895    }
 2896
 2897    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2898        self.leader_id
 2899    }
 2900
 2901    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2902        &self.buffer
 2903    }
 2904
 2905    pub fn project(&self) -> Option<&Entity<Project>> {
 2906        self.project.as_ref()
 2907    }
 2908
 2909    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2910        self.workspace.as_ref()?.0.upgrade()
 2911    }
 2912
 2913    /// Returns the workspace serialization ID if this editor should be serialized.
 2914    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2915        self.workspace
 2916            .as_ref()
 2917            .filter(|_| self.should_serialize_buffer())
 2918            .and_then(|workspace| workspace.1)
 2919    }
 2920
 2921    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2922        self.buffer().read(cx).title(cx)
 2923    }
 2924
 2925    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2926        let git_blame_gutter_max_author_length = self
 2927            .render_git_blame_gutter(cx)
 2928            .then(|| {
 2929                if let Some(blame) = self.blame.as_ref() {
 2930                    let max_author_length =
 2931                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2932                    Some(max_author_length)
 2933                } else {
 2934                    None
 2935                }
 2936            })
 2937            .flatten();
 2938
 2939        EditorSnapshot {
 2940            mode: self.mode.clone(),
 2941            show_gutter: self.show_gutter,
 2942            offset_content: self.offset_content,
 2943            show_line_numbers: self.show_line_numbers,
 2944            show_git_diff_gutter: self.show_git_diff_gutter,
 2945            show_code_actions: self.show_code_actions,
 2946            show_runnables: self.show_runnables,
 2947            show_breakpoints: self.show_breakpoints,
 2948            git_blame_gutter_max_author_length,
 2949            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2950            placeholder_display_snapshot: self
 2951                .placeholder_display_map
 2952                .as_ref()
 2953                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2954            scroll_anchor: self.scroll_manager.anchor(),
 2955            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2956            is_focused: self.focus_handle.is_focused(window),
 2957            current_line_highlight: self
 2958                .current_line_highlight
 2959                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2960            gutter_hovered: self.gutter_hovered,
 2961        }
 2962    }
 2963
 2964    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2965        self.buffer.read(cx).language_at(point, cx)
 2966    }
 2967
 2968    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2969        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2970    }
 2971
 2972    pub fn active_excerpt(
 2973        &self,
 2974        cx: &App,
 2975    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2976        self.buffer
 2977            .read(cx)
 2978            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2979    }
 2980
 2981    pub fn mode(&self) -> &EditorMode {
 2982        &self.mode
 2983    }
 2984
 2985    pub fn set_mode(&mut self, mode: EditorMode) {
 2986        self.mode = mode;
 2987    }
 2988
 2989    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2990        self.collaboration_hub.as_deref()
 2991    }
 2992
 2993    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2994        self.collaboration_hub = Some(hub);
 2995    }
 2996
 2997    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2998        self.in_project_search = in_project_search;
 2999    }
 3000
 3001    pub fn set_custom_context_menu(
 3002        &mut self,
 3003        f: impl 'static
 3004        + Fn(
 3005            &mut Self,
 3006            DisplayPoint,
 3007            &mut Window,
 3008            &mut Context<Self>,
 3009        ) -> Option<Entity<ui::ContextMenu>>,
 3010    ) {
 3011        self.custom_context_menu = Some(Box::new(f))
 3012    }
 3013
 3014    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3015        self.completion_provider = provider;
 3016    }
 3017
 3018    #[cfg(any(test, feature = "test-support"))]
 3019    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3020        self.completion_provider.clone()
 3021    }
 3022
 3023    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3024        self.semantics_provider.clone()
 3025    }
 3026
 3027    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3028        self.semantics_provider = provider;
 3029    }
 3030
 3031    pub fn set_edit_prediction_provider<T>(
 3032        &mut self,
 3033        provider: Option<Entity<T>>,
 3034        window: &mut Window,
 3035        cx: &mut Context<Self>,
 3036    ) where
 3037        T: EditPredictionDelegate,
 3038    {
 3039        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3040            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3041                if this.focus_handle.is_focused(window) {
 3042                    this.update_visible_edit_prediction(window, cx);
 3043                }
 3044            }),
 3045            provider: Arc::new(provider),
 3046        });
 3047        self.update_edit_prediction_settings(cx);
 3048        self.refresh_edit_prediction(false, false, window, cx);
 3049    }
 3050
 3051    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3052        self.placeholder_display_map
 3053            .as_ref()
 3054            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3055    }
 3056
 3057    pub fn set_placeholder_text(
 3058        &mut self,
 3059        placeholder_text: &str,
 3060        window: &mut Window,
 3061        cx: &mut Context<Self>,
 3062    ) {
 3063        let multibuffer = cx
 3064            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3065
 3066        let style = window.text_style();
 3067
 3068        self.placeholder_display_map = Some(cx.new(|cx| {
 3069            DisplayMap::new(
 3070                multibuffer,
 3071                style.font(),
 3072                style.font_size.to_pixels(window.rem_size()),
 3073                None,
 3074                FILE_HEADER_HEIGHT,
 3075                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3076                Default::default(),
 3077                DiagnosticSeverity::Off,
 3078                cx,
 3079            )
 3080        }));
 3081        cx.notify();
 3082    }
 3083
 3084    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3085        self.cursor_shape = cursor_shape;
 3086
 3087        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3088        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3089
 3090        cx.notify();
 3091    }
 3092
 3093    pub fn cursor_shape(&self) -> CursorShape {
 3094        self.cursor_shape
 3095    }
 3096
 3097    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3098        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3099    }
 3100
 3101    pub fn set_current_line_highlight(
 3102        &mut self,
 3103        current_line_highlight: Option<CurrentLineHighlight>,
 3104    ) {
 3105        self.current_line_highlight = current_line_highlight;
 3106    }
 3107
 3108    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3109        self.collapse_matches = collapse_matches;
 3110    }
 3111
 3112    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3113        if self.collapse_matches {
 3114            return range.start..range.start;
 3115        }
 3116        range.clone()
 3117    }
 3118
 3119    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3120        self.display_map.read(cx).clip_at_line_ends
 3121    }
 3122
 3123    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3124        if self.display_map.read(cx).clip_at_line_ends != clip {
 3125            self.display_map
 3126                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3127        }
 3128    }
 3129
 3130    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3131        self.input_enabled = input_enabled;
 3132    }
 3133
 3134    pub fn set_edit_predictions_hidden_for_vim_mode(
 3135        &mut self,
 3136        hidden: bool,
 3137        window: &mut Window,
 3138        cx: &mut Context<Self>,
 3139    ) {
 3140        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3141            self.edit_predictions_hidden_for_vim_mode = hidden;
 3142            if hidden {
 3143                self.update_visible_edit_prediction(window, cx);
 3144            } else {
 3145                self.refresh_edit_prediction(true, false, window, cx);
 3146            }
 3147        }
 3148    }
 3149
 3150    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3151        self.menu_edit_predictions_policy = value;
 3152    }
 3153
 3154    pub fn set_autoindent(&mut self, autoindent: bool) {
 3155        if autoindent {
 3156            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3157        } else {
 3158            self.autoindent_mode = None;
 3159        }
 3160    }
 3161
 3162    pub fn read_only(&self, cx: &App) -> bool {
 3163        self.read_only || self.buffer.read(cx).read_only()
 3164    }
 3165
 3166    pub fn set_read_only(&mut self, read_only: bool) {
 3167        self.read_only = read_only;
 3168    }
 3169
 3170    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3171        self.use_autoclose = autoclose;
 3172    }
 3173
 3174    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3175        self.use_auto_surround = auto_surround;
 3176    }
 3177
 3178    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3179        self.auto_replace_emoji_shortcode = auto_replace;
 3180    }
 3181
 3182    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3183        self.buffer_serialization = should_serialize.then(|| {
 3184            BufferSerialization::new(
 3185                ProjectSettings::get_global(cx)
 3186                    .session
 3187                    .restore_unsaved_buffers,
 3188            )
 3189        })
 3190    }
 3191
 3192    fn should_serialize_buffer(&self) -> bool {
 3193        self.buffer_serialization.is_some()
 3194    }
 3195
 3196    pub fn toggle_edit_predictions(
 3197        &mut self,
 3198        _: &ToggleEditPrediction,
 3199        window: &mut Window,
 3200        cx: &mut Context<Self>,
 3201    ) {
 3202        if self.show_edit_predictions_override.is_some() {
 3203            self.set_show_edit_predictions(None, window, cx);
 3204        } else {
 3205            let show_edit_predictions = !self.edit_predictions_enabled();
 3206            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3207        }
 3208    }
 3209
 3210    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3211        self.show_completions_on_input_override = show_completions_on_input;
 3212    }
 3213
 3214    pub fn set_show_edit_predictions(
 3215        &mut self,
 3216        show_edit_predictions: Option<bool>,
 3217        window: &mut Window,
 3218        cx: &mut Context<Self>,
 3219    ) {
 3220        self.show_edit_predictions_override = show_edit_predictions;
 3221        self.update_edit_prediction_settings(cx);
 3222
 3223        if let Some(false) = show_edit_predictions {
 3224            self.discard_edit_prediction(false, cx);
 3225        } else {
 3226            self.refresh_edit_prediction(false, true, window, cx);
 3227        }
 3228    }
 3229
 3230    fn edit_predictions_disabled_in_scope(
 3231        &self,
 3232        buffer: &Entity<Buffer>,
 3233        buffer_position: language::Anchor,
 3234        cx: &App,
 3235    ) -> bool {
 3236        let snapshot = buffer.read(cx).snapshot();
 3237        let settings = snapshot.settings_at(buffer_position, cx);
 3238
 3239        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3240            return false;
 3241        };
 3242
 3243        scope.override_name().is_some_and(|scope_name| {
 3244            settings
 3245                .edit_predictions_disabled_in
 3246                .iter()
 3247                .any(|s| s == scope_name)
 3248        })
 3249    }
 3250
 3251    pub fn set_use_modal_editing(&mut self, to: bool) {
 3252        self.use_modal_editing = to;
 3253    }
 3254
 3255    pub fn use_modal_editing(&self) -> bool {
 3256        self.use_modal_editing
 3257    }
 3258
 3259    fn selections_did_change(
 3260        &mut self,
 3261        local: bool,
 3262        old_cursor_position: &Anchor,
 3263        effects: SelectionEffects,
 3264        window: &mut Window,
 3265        cx: &mut Context<Self>,
 3266    ) {
 3267        window.invalidate_character_coordinates();
 3268
 3269        // Copy selections to primary selection buffer
 3270        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3271        if local {
 3272            let selections = self
 3273                .selections
 3274                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3275            let buffer_handle = self.buffer.read(cx).read(cx);
 3276
 3277            let mut text = String::new();
 3278            for (index, selection) in selections.iter().enumerate() {
 3279                let text_for_selection = buffer_handle
 3280                    .text_for_range(selection.start..selection.end)
 3281                    .collect::<String>();
 3282
 3283                text.push_str(&text_for_selection);
 3284                if index != selections.len() - 1 {
 3285                    text.push('\n');
 3286                }
 3287            }
 3288
 3289            if !text.is_empty() {
 3290                cx.write_to_primary(ClipboardItem::new_string(text));
 3291            }
 3292        }
 3293
 3294        let selection_anchors = self.selections.disjoint_anchors_arc();
 3295
 3296        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3297            self.buffer.update(cx, |buffer, cx| {
 3298                buffer.set_active_selections(
 3299                    &selection_anchors,
 3300                    self.selections.line_mode(),
 3301                    self.cursor_shape,
 3302                    cx,
 3303                )
 3304            });
 3305        }
 3306        let display_map = self
 3307            .display_map
 3308            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3309        let buffer = display_map.buffer_snapshot();
 3310        if self.selections.count() == 1 {
 3311            self.add_selections_state = None;
 3312        }
 3313        self.select_next_state = None;
 3314        self.select_prev_state = None;
 3315        self.select_syntax_node_history.try_clear();
 3316        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3317        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3318        self.take_rename(false, window, cx);
 3319
 3320        let newest_selection = self.selections.newest_anchor();
 3321        let new_cursor_position = newest_selection.head();
 3322        let selection_start = newest_selection.start;
 3323
 3324        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3325            self.push_to_nav_history(
 3326                *old_cursor_position,
 3327                Some(new_cursor_position.to_point(buffer)),
 3328                false,
 3329                effects.nav_history == Some(true),
 3330                cx,
 3331            );
 3332        }
 3333
 3334        if local {
 3335            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3336                self.register_buffer(buffer_id, cx);
 3337            }
 3338
 3339            let mut context_menu = self.context_menu.borrow_mut();
 3340            let completion_menu = match context_menu.as_ref() {
 3341                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3342                Some(CodeContextMenu::CodeActions(_)) => {
 3343                    *context_menu = None;
 3344                    None
 3345                }
 3346                None => None,
 3347            };
 3348            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3349            drop(context_menu);
 3350
 3351            if effects.completions
 3352                && let Some(completion_position) = completion_position
 3353            {
 3354                let start_offset = selection_start.to_offset(buffer);
 3355                let position_matches = start_offset == completion_position.to_offset(buffer);
 3356                let continue_showing = if position_matches {
 3357                    if self.snippet_stack.is_empty() {
 3358                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3359                            == Some(CharKind::Word)
 3360                    } else {
 3361                        // Snippet choices can be shown even when the cursor is in whitespace.
 3362                        // Dismissing the menu with actions like backspace is handled by
 3363                        // invalidation regions.
 3364                        true
 3365                    }
 3366                } else {
 3367                    false
 3368                };
 3369
 3370                if continue_showing {
 3371                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3372                } else {
 3373                    self.hide_context_menu(window, cx);
 3374                }
 3375            }
 3376
 3377            hide_hover(self, cx);
 3378
 3379            if old_cursor_position.to_display_point(&display_map).row()
 3380                != new_cursor_position.to_display_point(&display_map).row()
 3381            {
 3382                self.available_code_actions.take();
 3383            }
 3384            self.refresh_code_actions(window, cx);
 3385            self.refresh_document_highlights(cx);
 3386            refresh_linked_ranges(self, window, cx);
 3387
 3388            self.refresh_selected_text_highlights(false, window, cx);
 3389            self.refresh_matching_bracket_highlights(window, cx);
 3390            self.update_visible_edit_prediction(window, cx);
 3391            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3392            self.inline_blame_popover.take();
 3393            if self.git_blame_inline_enabled {
 3394                self.start_inline_blame_timer(window, cx);
 3395            }
 3396        }
 3397
 3398        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3399        cx.emit(EditorEvent::SelectionsChanged { local });
 3400
 3401        let selections = &self.selections.disjoint_anchors_arc();
 3402        if selections.len() == 1 {
 3403            cx.emit(SearchEvent::ActiveMatchChanged)
 3404        }
 3405        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3406            let inmemory_selections = selections
 3407                .iter()
 3408                .map(|s| {
 3409                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3410                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3411                })
 3412                .collect();
 3413            self.update_restoration_data(cx, |data| {
 3414                data.selections = inmemory_selections;
 3415            });
 3416
 3417            if WorkspaceSettings::get(None, cx).restore_on_startup
 3418                != RestoreOnStartupBehavior::EmptyTab
 3419                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3420            {
 3421                let snapshot = self.buffer().read(cx).snapshot(cx);
 3422                let selections = selections.clone();
 3423                let background_executor = cx.background_executor().clone();
 3424                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3425                self.serialize_selections = cx.background_spawn(async move {
 3426                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3427                    let db_selections = selections
 3428                        .iter()
 3429                        .map(|selection| {
 3430                            (
 3431                                selection.start.to_offset(&snapshot).0,
 3432                                selection.end.to_offset(&snapshot).0,
 3433                            )
 3434                        })
 3435                        .collect();
 3436
 3437                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3438                        .await
 3439                        .with_context(|| {
 3440                            format!(
 3441                                "persisting editor selections for editor {editor_id}, \
 3442                                workspace {workspace_id:?}"
 3443                            )
 3444                        })
 3445                        .log_err();
 3446                });
 3447            }
 3448        }
 3449
 3450        cx.notify();
 3451    }
 3452
 3453    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3454        use text::ToOffset as _;
 3455        use text::ToPoint as _;
 3456
 3457        if self.mode.is_minimap()
 3458            || WorkspaceSettings::get(None, cx).restore_on_startup
 3459                == RestoreOnStartupBehavior::EmptyTab
 3460        {
 3461            return;
 3462        }
 3463
 3464        if !self.buffer().read(cx).is_singleton() {
 3465            return;
 3466        }
 3467
 3468        let display_snapshot = self
 3469            .display_map
 3470            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3471        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3472            return;
 3473        };
 3474        let inmemory_folds = display_snapshot
 3475            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3476            .map(|fold| {
 3477                fold.range.start.text_anchor.to_point(&snapshot)
 3478                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3479            })
 3480            .collect();
 3481        self.update_restoration_data(cx, |data| {
 3482            data.folds = inmemory_folds;
 3483        });
 3484
 3485        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3486            return;
 3487        };
 3488        let background_executor = cx.background_executor().clone();
 3489        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3490        let db_folds = display_snapshot
 3491            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3492            .map(|fold| {
 3493                (
 3494                    fold.range.start.text_anchor.to_offset(&snapshot),
 3495                    fold.range.end.text_anchor.to_offset(&snapshot),
 3496                )
 3497            })
 3498            .collect();
 3499        self.serialize_folds = cx.background_spawn(async move {
 3500            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3501            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3502                .await
 3503                .with_context(|| {
 3504                    format!(
 3505                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3506                    )
 3507                })
 3508                .log_err();
 3509        });
 3510    }
 3511
 3512    pub fn sync_selections(
 3513        &mut self,
 3514        other: Entity<Editor>,
 3515        cx: &mut Context<Self>,
 3516    ) -> gpui::Subscription {
 3517        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3518        if !other_selections.is_empty() {
 3519            self.selections
 3520                .change_with(&self.display_snapshot(cx), |selections| {
 3521                    selections.select_anchors(other_selections);
 3522                });
 3523        }
 3524
 3525        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3526            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3527                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3528                if other_selections.is_empty() {
 3529                    return;
 3530                }
 3531                let snapshot = this.display_snapshot(cx);
 3532                this.selections.change_with(&snapshot, |selections| {
 3533                    selections.select_anchors(other_selections);
 3534                });
 3535            }
 3536        });
 3537
 3538        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3539            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3540                let these_selections = this.selections.disjoint_anchors().to_vec();
 3541                if these_selections.is_empty() {
 3542                    return;
 3543                }
 3544                other.update(cx, |other_editor, cx| {
 3545                    let snapshot = other_editor.display_snapshot(cx);
 3546                    other_editor
 3547                        .selections
 3548                        .change_with(&snapshot, |selections| {
 3549                            selections.select_anchors(these_selections);
 3550                        })
 3551                });
 3552            }
 3553        });
 3554
 3555        Subscription::join(other_subscription, this_subscription)
 3556    }
 3557
 3558    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3559        if self.buffer().read(cx).is_singleton() {
 3560            return;
 3561        }
 3562        let snapshot = self.buffer.read(cx).snapshot(cx);
 3563        let buffer_ids: HashSet<BufferId> = self
 3564            .selections
 3565            .disjoint_anchor_ranges()
 3566            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3567            .collect();
 3568        for buffer_id in buffer_ids {
 3569            self.unfold_buffer(buffer_id, cx);
 3570        }
 3571    }
 3572
 3573    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3574    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3575    /// effects of selection change occur at the end of the transaction.
 3576    pub fn change_selections<R>(
 3577        &mut self,
 3578        effects: SelectionEffects,
 3579        window: &mut Window,
 3580        cx: &mut Context<Self>,
 3581        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3582    ) -> R {
 3583        let snapshot = self.display_snapshot(cx);
 3584        if let Some(state) = &mut self.deferred_selection_effects_state {
 3585            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3586            state.effects.completions = effects.completions;
 3587            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3588            let (changed, result) = self.selections.change_with(&snapshot, change);
 3589            state.changed |= changed;
 3590            return result;
 3591        }
 3592        let mut state = DeferredSelectionEffectsState {
 3593            changed: false,
 3594            effects,
 3595            old_cursor_position: self.selections.newest_anchor().head(),
 3596            history_entry: SelectionHistoryEntry {
 3597                selections: self.selections.disjoint_anchors_arc(),
 3598                select_next_state: self.select_next_state.clone(),
 3599                select_prev_state: self.select_prev_state.clone(),
 3600                add_selections_state: self.add_selections_state.clone(),
 3601            },
 3602        };
 3603        let (changed, result) = self.selections.change_with(&snapshot, change);
 3604        state.changed = state.changed || changed;
 3605        if self.defer_selection_effects {
 3606            self.deferred_selection_effects_state = Some(state);
 3607        } else {
 3608            self.apply_selection_effects(state, window, cx);
 3609        }
 3610        result
 3611    }
 3612
 3613    /// Defers the effects of selection change, so that the effects of multiple calls to
 3614    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3615    /// to selection history and the state of popovers based on selection position aren't
 3616    /// erroneously updated.
 3617    pub fn with_selection_effects_deferred<R>(
 3618        &mut self,
 3619        window: &mut Window,
 3620        cx: &mut Context<Self>,
 3621        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3622    ) -> R {
 3623        let already_deferred = self.defer_selection_effects;
 3624        self.defer_selection_effects = true;
 3625        let result = update(self, window, cx);
 3626        if !already_deferred {
 3627            self.defer_selection_effects = false;
 3628            if let Some(state) = self.deferred_selection_effects_state.take() {
 3629                self.apply_selection_effects(state, window, cx);
 3630            }
 3631        }
 3632        result
 3633    }
 3634
 3635    fn apply_selection_effects(
 3636        &mut self,
 3637        state: DeferredSelectionEffectsState,
 3638        window: &mut Window,
 3639        cx: &mut Context<Self>,
 3640    ) {
 3641        if state.changed {
 3642            self.selection_history.push(state.history_entry);
 3643
 3644            if let Some(autoscroll) = state.effects.scroll {
 3645                self.request_autoscroll(autoscroll, cx);
 3646            }
 3647
 3648            let old_cursor_position = &state.old_cursor_position;
 3649
 3650            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3651
 3652            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3653                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3654            }
 3655        }
 3656    }
 3657
 3658    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3659    where
 3660        I: IntoIterator<Item = (Range<S>, T)>,
 3661        S: ToOffset,
 3662        T: Into<Arc<str>>,
 3663    {
 3664        if self.read_only(cx) {
 3665            return;
 3666        }
 3667
 3668        self.buffer
 3669            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3670    }
 3671
 3672    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3673    where
 3674        I: IntoIterator<Item = (Range<S>, T)>,
 3675        S: ToOffset,
 3676        T: Into<Arc<str>>,
 3677    {
 3678        if self.read_only(cx) {
 3679            return;
 3680        }
 3681
 3682        self.buffer.update(cx, |buffer, cx| {
 3683            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3684        });
 3685    }
 3686
 3687    pub fn edit_with_block_indent<I, S, T>(
 3688        &mut self,
 3689        edits: I,
 3690        original_indent_columns: Vec<Option<u32>>,
 3691        cx: &mut Context<Self>,
 3692    ) where
 3693        I: IntoIterator<Item = (Range<S>, T)>,
 3694        S: ToOffset,
 3695        T: Into<Arc<str>>,
 3696    {
 3697        if self.read_only(cx) {
 3698            return;
 3699        }
 3700
 3701        self.buffer.update(cx, |buffer, cx| {
 3702            buffer.edit(
 3703                edits,
 3704                Some(AutoindentMode::Block {
 3705                    original_indent_columns,
 3706                }),
 3707                cx,
 3708            )
 3709        });
 3710    }
 3711
 3712    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3713        self.hide_context_menu(window, cx);
 3714
 3715        match phase {
 3716            SelectPhase::Begin {
 3717                position,
 3718                add,
 3719                click_count,
 3720            } => self.begin_selection(position, add, click_count, window, cx),
 3721            SelectPhase::BeginColumnar {
 3722                position,
 3723                goal_column,
 3724                reset,
 3725                mode,
 3726            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3727            SelectPhase::Extend {
 3728                position,
 3729                click_count,
 3730            } => self.extend_selection(position, click_count, window, cx),
 3731            SelectPhase::Update {
 3732                position,
 3733                goal_column,
 3734                scroll_delta,
 3735            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3736            SelectPhase::End => self.end_selection(window, cx),
 3737        }
 3738    }
 3739
 3740    fn extend_selection(
 3741        &mut self,
 3742        position: DisplayPoint,
 3743        click_count: usize,
 3744        window: &mut Window,
 3745        cx: &mut Context<Self>,
 3746    ) {
 3747        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3748        let tail = self
 3749            .selections
 3750            .newest::<MultiBufferOffset>(&display_map)
 3751            .tail();
 3752        let click_count = click_count.max(match self.selections.select_mode() {
 3753            SelectMode::Character => 1,
 3754            SelectMode::Word(_) => 2,
 3755            SelectMode::Line(_) => 3,
 3756            SelectMode::All => 4,
 3757        });
 3758        self.begin_selection(position, false, click_count, window, cx);
 3759
 3760        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3761
 3762        let current_selection = match self.selections.select_mode() {
 3763            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3764            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3765        };
 3766
 3767        let mut pending_selection = self
 3768            .selections
 3769            .pending_anchor()
 3770            .cloned()
 3771            .expect("extend_selection not called with pending selection");
 3772
 3773        if pending_selection
 3774            .start
 3775            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3776            == Ordering::Greater
 3777        {
 3778            pending_selection.start = current_selection.start;
 3779        }
 3780        if pending_selection
 3781            .end
 3782            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3783            == Ordering::Less
 3784        {
 3785            pending_selection.end = current_selection.end;
 3786            pending_selection.reversed = true;
 3787        }
 3788
 3789        let mut pending_mode = self.selections.pending_mode().unwrap();
 3790        match &mut pending_mode {
 3791            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3792            _ => {}
 3793        }
 3794
 3795        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3796            SelectionEffects::scroll(Autoscroll::fit())
 3797        } else {
 3798            SelectionEffects::no_scroll()
 3799        };
 3800
 3801        self.change_selections(effects, window, cx, |s| {
 3802            s.set_pending(pending_selection.clone(), pending_mode);
 3803            s.set_is_extending(true);
 3804        });
 3805    }
 3806
 3807    fn begin_selection(
 3808        &mut self,
 3809        position: DisplayPoint,
 3810        add: bool,
 3811        click_count: usize,
 3812        window: &mut Window,
 3813        cx: &mut Context<Self>,
 3814    ) {
 3815        if !self.focus_handle.is_focused(window) {
 3816            self.last_focused_descendant = None;
 3817            window.focus(&self.focus_handle, cx);
 3818        }
 3819
 3820        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3821        let buffer = display_map.buffer_snapshot();
 3822        let position = display_map.clip_point(position, Bias::Left);
 3823
 3824        let start;
 3825        let end;
 3826        let mode;
 3827        let mut auto_scroll;
 3828        match click_count {
 3829            1 => {
 3830                start = buffer.anchor_before(position.to_point(&display_map));
 3831                end = start;
 3832                mode = SelectMode::Character;
 3833                auto_scroll = true;
 3834            }
 3835            2 => {
 3836                let position = display_map
 3837                    .clip_point(position, Bias::Left)
 3838                    .to_offset(&display_map, Bias::Left);
 3839                let (range, _) = buffer.surrounding_word(position, None);
 3840                start = buffer.anchor_before(range.start);
 3841                end = buffer.anchor_before(range.end);
 3842                mode = SelectMode::Word(start..end);
 3843                auto_scroll = true;
 3844            }
 3845            3 => {
 3846                let position = display_map
 3847                    .clip_point(position, Bias::Left)
 3848                    .to_point(&display_map);
 3849                let line_start = display_map.prev_line_boundary(position).0;
 3850                let next_line_start = buffer.clip_point(
 3851                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3852                    Bias::Left,
 3853                );
 3854                start = buffer.anchor_before(line_start);
 3855                end = buffer.anchor_before(next_line_start);
 3856                mode = SelectMode::Line(start..end);
 3857                auto_scroll = true;
 3858            }
 3859            _ => {
 3860                start = buffer.anchor_before(MultiBufferOffset(0));
 3861                end = buffer.anchor_before(buffer.len());
 3862                mode = SelectMode::All;
 3863                auto_scroll = false;
 3864            }
 3865        }
 3866        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3867
 3868        let point_to_delete: Option<usize> = {
 3869            let selected_points: Vec<Selection<Point>> =
 3870                self.selections.disjoint_in_range(start..end, &display_map);
 3871
 3872            if !add || click_count > 1 {
 3873                None
 3874            } else if !selected_points.is_empty() {
 3875                Some(selected_points[0].id)
 3876            } else {
 3877                let clicked_point_already_selected =
 3878                    self.selections.disjoint_anchors().iter().find(|selection| {
 3879                        selection.start.to_point(buffer) == start.to_point(buffer)
 3880                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3881                    });
 3882
 3883                clicked_point_already_selected.map(|selection| selection.id)
 3884            }
 3885        };
 3886
 3887        let selections_count = self.selections.count();
 3888        let effects = if auto_scroll {
 3889            SelectionEffects::default()
 3890        } else {
 3891            SelectionEffects::no_scroll()
 3892        };
 3893
 3894        self.change_selections(effects, window, cx, |s| {
 3895            if let Some(point_to_delete) = point_to_delete {
 3896                s.delete(point_to_delete);
 3897
 3898                if selections_count == 1 {
 3899                    s.set_pending_anchor_range(start..end, mode);
 3900                }
 3901            } else {
 3902                if !add {
 3903                    s.clear_disjoint();
 3904                }
 3905
 3906                s.set_pending_anchor_range(start..end, mode);
 3907            }
 3908        });
 3909    }
 3910
 3911    fn begin_columnar_selection(
 3912        &mut self,
 3913        position: DisplayPoint,
 3914        goal_column: u32,
 3915        reset: bool,
 3916        mode: ColumnarMode,
 3917        window: &mut Window,
 3918        cx: &mut Context<Self>,
 3919    ) {
 3920        if !self.focus_handle.is_focused(window) {
 3921            self.last_focused_descendant = None;
 3922            window.focus(&self.focus_handle, cx);
 3923        }
 3924
 3925        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3926
 3927        if reset {
 3928            let pointer_position = display_map
 3929                .buffer_snapshot()
 3930                .anchor_before(position.to_point(&display_map));
 3931
 3932            self.change_selections(
 3933                SelectionEffects::scroll(Autoscroll::newest()),
 3934                window,
 3935                cx,
 3936                |s| {
 3937                    s.clear_disjoint();
 3938                    s.set_pending_anchor_range(
 3939                        pointer_position..pointer_position,
 3940                        SelectMode::Character,
 3941                    );
 3942                },
 3943            );
 3944        };
 3945
 3946        let tail = self.selections.newest::<Point>(&display_map).tail();
 3947        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3948        self.columnar_selection_state = match mode {
 3949            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3950                selection_tail: selection_anchor,
 3951                display_point: if reset {
 3952                    if position.column() != goal_column {
 3953                        Some(DisplayPoint::new(position.row(), goal_column))
 3954                    } else {
 3955                        None
 3956                    }
 3957                } else {
 3958                    None
 3959                },
 3960            }),
 3961            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3962                selection_tail: selection_anchor,
 3963            }),
 3964        };
 3965
 3966        if !reset {
 3967            self.select_columns(position, goal_column, &display_map, window, cx);
 3968        }
 3969    }
 3970
 3971    fn update_selection(
 3972        &mut self,
 3973        position: DisplayPoint,
 3974        goal_column: u32,
 3975        scroll_delta: gpui::Point<f32>,
 3976        window: &mut Window,
 3977        cx: &mut Context<Self>,
 3978    ) {
 3979        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3980
 3981        if self.columnar_selection_state.is_some() {
 3982            self.select_columns(position, goal_column, &display_map, window, cx);
 3983        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3984            let buffer = display_map.buffer_snapshot();
 3985            let head;
 3986            let tail;
 3987            let mode = self.selections.pending_mode().unwrap();
 3988            match &mode {
 3989                SelectMode::Character => {
 3990                    head = position.to_point(&display_map);
 3991                    tail = pending.tail().to_point(buffer);
 3992                }
 3993                SelectMode::Word(original_range) => {
 3994                    let offset = display_map
 3995                        .clip_point(position, Bias::Left)
 3996                        .to_offset(&display_map, Bias::Left);
 3997                    let original_range = original_range.to_offset(buffer);
 3998
 3999                    let head_offset = if buffer.is_inside_word(offset, None)
 4000                        || original_range.contains(&offset)
 4001                    {
 4002                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4003                        if word_range.start < original_range.start {
 4004                            word_range.start
 4005                        } else {
 4006                            word_range.end
 4007                        }
 4008                    } else {
 4009                        offset
 4010                    };
 4011
 4012                    head = head_offset.to_point(buffer);
 4013                    if head_offset <= original_range.start {
 4014                        tail = original_range.end.to_point(buffer);
 4015                    } else {
 4016                        tail = original_range.start.to_point(buffer);
 4017                    }
 4018                }
 4019                SelectMode::Line(original_range) => {
 4020                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4021
 4022                    let position = display_map
 4023                        .clip_point(position, Bias::Left)
 4024                        .to_point(&display_map);
 4025                    let line_start = display_map.prev_line_boundary(position).0;
 4026                    let next_line_start = buffer.clip_point(
 4027                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4028                        Bias::Left,
 4029                    );
 4030
 4031                    if line_start < original_range.start {
 4032                        head = line_start
 4033                    } else {
 4034                        head = next_line_start
 4035                    }
 4036
 4037                    if head <= original_range.start {
 4038                        tail = original_range.end;
 4039                    } else {
 4040                        tail = original_range.start;
 4041                    }
 4042                }
 4043                SelectMode::All => {
 4044                    return;
 4045                }
 4046            };
 4047
 4048            if head < tail {
 4049                pending.start = buffer.anchor_before(head);
 4050                pending.end = buffer.anchor_before(tail);
 4051                pending.reversed = true;
 4052            } else {
 4053                pending.start = buffer.anchor_before(tail);
 4054                pending.end = buffer.anchor_before(head);
 4055                pending.reversed = false;
 4056            }
 4057
 4058            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4059                s.set_pending(pending.clone(), mode);
 4060            });
 4061        } else {
 4062            log::error!("update_selection dispatched with no pending selection");
 4063            return;
 4064        }
 4065
 4066        self.apply_scroll_delta(scroll_delta, window, cx);
 4067        cx.notify();
 4068    }
 4069
 4070    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4071        self.columnar_selection_state.take();
 4072        if let Some(pending_mode) = self.selections.pending_mode() {
 4073            let selections = self
 4074                .selections
 4075                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4076            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4077                s.select(selections);
 4078                s.clear_pending();
 4079                if s.is_extending() {
 4080                    s.set_is_extending(false);
 4081                } else {
 4082                    s.set_select_mode(pending_mode);
 4083                }
 4084            });
 4085        }
 4086    }
 4087
 4088    fn select_columns(
 4089        &mut self,
 4090        head: DisplayPoint,
 4091        goal_column: u32,
 4092        display_map: &DisplaySnapshot,
 4093        window: &mut Window,
 4094        cx: &mut Context<Self>,
 4095    ) {
 4096        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4097            return;
 4098        };
 4099
 4100        let tail = match columnar_state {
 4101            ColumnarSelectionState::FromMouse {
 4102                selection_tail,
 4103                display_point,
 4104            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4105            ColumnarSelectionState::FromSelection { selection_tail } => {
 4106                selection_tail.to_display_point(display_map)
 4107            }
 4108        };
 4109
 4110        let start_row = cmp::min(tail.row(), head.row());
 4111        let end_row = cmp::max(tail.row(), head.row());
 4112        let start_column = cmp::min(tail.column(), goal_column);
 4113        let end_column = cmp::max(tail.column(), goal_column);
 4114        let reversed = start_column < tail.column();
 4115
 4116        let selection_ranges = (start_row.0..=end_row.0)
 4117            .map(DisplayRow)
 4118            .filter_map(|row| {
 4119                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4120                    || start_column <= display_map.line_len(row))
 4121                    && !display_map.is_block_line(row)
 4122                {
 4123                    let start = display_map
 4124                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4125                        .to_point(display_map);
 4126                    let end = display_map
 4127                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4128                        .to_point(display_map);
 4129                    if reversed {
 4130                        Some(end..start)
 4131                    } else {
 4132                        Some(start..end)
 4133                    }
 4134                } else {
 4135                    None
 4136                }
 4137            })
 4138            .collect::<Vec<_>>();
 4139        if selection_ranges.is_empty() {
 4140            return;
 4141        }
 4142
 4143        let ranges = match columnar_state {
 4144            ColumnarSelectionState::FromMouse { .. } => {
 4145                let mut non_empty_ranges = selection_ranges
 4146                    .iter()
 4147                    .filter(|selection_range| selection_range.start != selection_range.end)
 4148                    .peekable();
 4149                if non_empty_ranges.peek().is_some() {
 4150                    non_empty_ranges.cloned().collect()
 4151                } else {
 4152                    selection_ranges
 4153                }
 4154            }
 4155            _ => selection_ranges,
 4156        };
 4157
 4158        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4159            s.select_ranges(ranges);
 4160        });
 4161        cx.notify();
 4162    }
 4163
 4164    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4165        self.selections
 4166            .all_adjusted(snapshot)
 4167            .iter()
 4168            .any(|selection| !selection.is_empty())
 4169    }
 4170
 4171    pub fn has_pending_nonempty_selection(&self) -> bool {
 4172        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4173            Some(Selection { start, end, .. }) => start != end,
 4174            None => false,
 4175        };
 4176
 4177        pending_nonempty_selection
 4178            || (self.columnar_selection_state.is_some()
 4179                && self.selections.disjoint_anchors().len() > 1)
 4180    }
 4181
 4182    pub fn has_pending_selection(&self) -> bool {
 4183        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4184    }
 4185
 4186    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4187        self.selection_mark_mode = false;
 4188        self.selection_drag_state = SelectionDragState::None;
 4189
 4190        if self.dismiss_menus_and_popups(true, window, cx) {
 4191            cx.notify();
 4192            return;
 4193        }
 4194        if self.clear_expanded_diff_hunks(cx) {
 4195            cx.notify();
 4196            return;
 4197        }
 4198        if self.show_git_blame_gutter {
 4199            self.show_git_blame_gutter = false;
 4200            cx.notify();
 4201            return;
 4202        }
 4203
 4204        if self.mode.is_full()
 4205            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4206        {
 4207            cx.notify();
 4208            return;
 4209        }
 4210
 4211        cx.propagate();
 4212    }
 4213
 4214    pub fn dismiss_menus_and_popups(
 4215        &mut self,
 4216        is_user_requested: bool,
 4217        window: &mut Window,
 4218        cx: &mut Context<Self>,
 4219    ) -> bool {
 4220        let mut dismissed = false;
 4221
 4222        dismissed |= self.take_rename(false, window, cx).is_some();
 4223        dismissed |= self.hide_blame_popover(true, cx);
 4224        dismissed |= hide_hover(self, cx);
 4225        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4226        dismissed |= self.hide_context_menu(window, cx).is_some();
 4227        dismissed |= self.mouse_context_menu.take().is_some();
 4228        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4229        dismissed |= self.snippet_stack.pop().is_some();
 4230
 4231        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4232            self.dismiss_diagnostics(cx);
 4233            dismissed = true;
 4234        }
 4235
 4236        dismissed
 4237    }
 4238
 4239    fn linked_editing_ranges_for(
 4240        &self,
 4241        selection: Range<text::Anchor>,
 4242        cx: &App,
 4243    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4244        if self.linked_edit_ranges.is_empty() {
 4245            return None;
 4246        }
 4247        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4248            selection.end.buffer_id.and_then(|end_buffer_id| {
 4249                if selection.start.buffer_id != Some(end_buffer_id) {
 4250                    return None;
 4251                }
 4252                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4253                let snapshot = buffer.read(cx).snapshot();
 4254                self.linked_edit_ranges
 4255                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4256                    .map(|ranges| (ranges, snapshot, buffer))
 4257            })?;
 4258        use text::ToOffset as TO;
 4259        // find offset from the start of current range to current cursor position
 4260        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4261
 4262        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4263        let start_difference = start_offset - start_byte_offset;
 4264        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4265        let end_difference = end_offset - start_byte_offset;
 4266        // Current range has associated linked ranges.
 4267        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4268        for range in linked_ranges.iter() {
 4269            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4270            let end_offset = start_offset + end_difference;
 4271            let start_offset = start_offset + start_difference;
 4272            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4273                continue;
 4274            }
 4275            if self.selections.disjoint_anchor_ranges().any(|s| {
 4276                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4277                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4278                {
 4279                    return false;
 4280                }
 4281                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4282                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4283            }) {
 4284                continue;
 4285            }
 4286            let start = buffer_snapshot.anchor_after(start_offset);
 4287            let end = buffer_snapshot.anchor_after(end_offset);
 4288            linked_edits
 4289                .entry(buffer.clone())
 4290                .or_default()
 4291                .push(start..end);
 4292        }
 4293        Some(linked_edits)
 4294    }
 4295
 4296    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4297        let text: Arc<str> = text.into();
 4298
 4299        if self.read_only(cx) {
 4300            return;
 4301        }
 4302
 4303        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4304
 4305        self.unfold_buffers_with_selections(cx);
 4306
 4307        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4308        let mut bracket_inserted = false;
 4309        let mut edits = Vec::new();
 4310        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4311        let mut new_selections = Vec::with_capacity(selections.len());
 4312        let mut new_autoclose_regions = Vec::new();
 4313        let snapshot = self.buffer.read(cx).read(cx);
 4314        let mut clear_linked_edit_ranges = false;
 4315
 4316        for (selection, autoclose_region) in
 4317            self.selections_with_autoclose_regions(selections, &snapshot)
 4318        {
 4319            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4320                // Determine if the inserted text matches the opening or closing
 4321                // bracket of any of this language's bracket pairs.
 4322                let mut bracket_pair = None;
 4323                let mut is_bracket_pair_start = false;
 4324                let mut is_bracket_pair_end = false;
 4325                if !text.is_empty() {
 4326                    let mut bracket_pair_matching_end = None;
 4327                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4328                    //  and they are removing the character that triggered IME popup.
 4329                    for (pair, enabled) in scope.brackets() {
 4330                        if !pair.close && !pair.surround {
 4331                            continue;
 4332                        }
 4333
 4334                        if enabled && pair.start.ends_with(text.as_ref()) {
 4335                            let prefix_len = pair.start.len() - text.len();
 4336                            let preceding_text_matches_prefix = prefix_len == 0
 4337                                || (selection.start.column >= (prefix_len as u32)
 4338                                    && snapshot.contains_str_at(
 4339                                        Point::new(
 4340                                            selection.start.row,
 4341                                            selection.start.column - (prefix_len as u32),
 4342                                        ),
 4343                                        &pair.start[..prefix_len],
 4344                                    ));
 4345                            if preceding_text_matches_prefix {
 4346                                bracket_pair = Some(pair.clone());
 4347                                is_bracket_pair_start = true;
 4348                                break;
 4349                            }
 4350                        }
 4351                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4352                        {
 4353                            // take first bracket pair matching end, but don't break in case a later bracket
 4354                            // pair matches start
 4355                            bracket_pair_matching_end = Some(pair.clone());
 4356                        }
 4357                    }
 4358                    if let Some(end) = bracket_pair_matching_end
 4359                        && bracket_pair.is_none()
 4360                    {
 4361                        bracket_pair = Some(end);
 4362                        is_bracket_pair_end = true;
 4363                    }
 4364                }
 4365
 4366                if let Some(bracket_pair) = bracket_pair {
 4367                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4368                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4369                    let auto_surround =
 4370                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4371                    if selection.is_empty() {
 4372                        if is_bracket_pair_start {
 4373                            // If the inserted text is a suffix of an opening bracket and the
 4374                            // selection is preceded by the rest of the opening bracket, then
 4375                            // insert the closing bracket.
 4376                            let following_text_allows_autoclose = snapshot
 4377                                .chars_at(selection.start)
 4378                                .next()
 4379                                .is_none_or(|c| scope.should_autoclose_before(c));
 4380
 4381                            let preceding_text_allows_autoclose = selection.start.column == 0
 4382                                || snapshot
 4383                                    .reversed_chars_at(selection.start)
 4384                                    .next()
 4385                                    .is_none_or(|c| {
 4386                                        bracket_pair.start != bracket_pair.end
 4387                                            || !snapshot
 4388                                                .char_classifier_at(selection.start)
 4389                                                .is_word(c)
 4390                                    });
 4391
 4392                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4393                                && bracket_pair.start.len() == 1
 4394                            {
 4395                                let target = bracket_pair.start.chars().next().unwrap();
 4396                                let mut byte_offset = 0u32;
 4397                                let current_line_count = snapshot
 4398                                    .reversed_chars_at(selection.start)
 4399                                    .take_while(|&c| c != '\n')
 4400                                    .filter(|c| {
 4401                                        byte_offset += c.len_utf8() as u32;
 4402                                        if *c != target {
 4403                                            return false;
 4404                                        }
 4405
 4406                                        let point = Point::new(
 4407                                            selection.start.row,
 4408                                            selection.start.column.saturating_sub(byte_offset),
 4409                                        );
 4410
 4411                                        let is_enabled = snapshot
 4412                                            .language_scope_at(point)
 4413                                            .and_then(|scope| {
 4414                                                scope
 4415                                                    .brackets()
 4416                                                    .find(|(pair, _)| {
 4417                                                        pair.start == bracket_pair.start
 4418                                                    })
 4419                                                    .map(|(_, enabled)| enabled)
 4420                                            })
 4421                                            .unwrap_or(true);
 4422
 4423                                        let is_delimiter = snapshot
 4424                                            .language_scope_at(Point::new(
 4425                                                point.row,
 4426                                                point.column + 1,
 4427                                            ))
 4428                                            .and_then(|scope| {
 4429                                                scope
 4430                                                    .brackets()
 4431                                                    .find(|(pair, _)| {
 4432                                                        pair.start == bracket_pair.start
 4433                                                    })
 4434                                                    .map(|(_, enabled)| !enabled)
 4435                                            })
 4436                                            .unwrap_or(false);
 4437
 4438                                        is_enabled && !is_delimiter
 4439                                    })
 4440                                    .count();
 4441                                current_line_count % 2 == 1
 4442                            } else {
 4443                                false
 4444                            };
 4445
 4446                            if autoclose
 4447                                && bracket_pair.close
 4448                                && following_text_allows_autoclose
 4449                                && preceding_text_allows_autoclose
 4450                                && !is_closing_quote
 4451                            {
 4452                                let anchor = snapshot.anchor_before(selection.end);
 4453                                new_selections.push((selection.map(|_| anchor), text.len()));
 4454                                new_autoclose_regions.push((
 4455                                    anchor,
 4456                                    text.len(),
 4457                                    selection.id,
 4458                                    bracket_pair.clone(),
 4459                                ));
 4460                                edits.push((
 4461                                    selection.range(),
 4462                                    format!("{}{}", text, bracket_pair.end).into(),
 4463                                ));
 4464                                bracket_inserted = true;
 4465                                continue;
 4466                            }
 4467                        }
 4468
 4469                        if let Some(region) = autoclose_region {
 4470                            // If the selection is followed by an auto-inserted closing bracket,
 4471                            // then don't insert that closing bracket again; just move the selection
 4472                            // past the closing bracket.
 4473                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4474                                && text.as_ref() == region.pair.end.as_str()
 4475                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4476                            if should_skip {
 4477                                let anchor = snapshot.anchor_after(selection.end);
 4478                                new_selections
 4479                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4480                                continue;
 4481                            }
 4482                        }
 4483
 4484                        let always_treat_brackets_as_autoclosed = snapshot
 4485                            .language_settings_at(selection.start, cx)
 4486                            .always_treat_brackets_as_autoclosed;
 4487                        if always_treat_brackets_as_autoclosed
 4488                            && is_bracket_pair_end
 4489                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4490                        {
 4491                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4492                            // and the inserted text is a closing bracket and the selection is followed
 4493                            // by the closing bracket then move the selection past the closing bracket.
 4494                            let anchor = snapshot.anchor_after(selection.end);
 4495                            new_selections.push((selection.map(|_| anchor), text.len()));
 4496                            continue;
 4497                        }
 4498                    }
 4499                    // If an opening bracket is 1 character long and is typed while
 4500                    // text is selected, then surround that text with the bracket pair.
 4501                    else if auto_surround
 4502                        && bracket_pair.surround
 4503                        && is_bracket_pair_start
 4504                        && bracket_pair.start.chars().count() == 1
 4505                    {
 4506                        edits.push((selection.start..selection.start, text.clone()));
 4507                        edits.push((
 4508                            selection.end..selection.end,
 4509                            bracket_pair.end.as_str().into(),
 4510                        ));
 4511                        bracket_inserted = true;
 4512                        new_selections.push((
 4513                            Selection {
 4514                                id: selection.id,
 4515                                start: snapshot.anchor_after(selection.start),
 4516                                end: snapshot.anchor_before(selection.end),
 4517                                reversed: selection.reversed,
 4518                                goal: selection.goal,
 4519                            },
 4520                            0,
 4521                        ));
 4522                        continue;
 4523                    }
 4524                }
 4525            }
 4526
 4527            if self.auto_replace_emoji_shortcode
 4528                && selection.is_empty()
 4529                && text.as_ref().ends_with(':')
 4530                && let Some(possible_emoji_short_code) =
 4531                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4532                && !possible_emoji_short_code.is_empty()
 4533                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4534            {
 4535                let emoji_shortcode_start = Point::new(
 4536                    selection.start.row,
 4537                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4538                );
 4539
 4540                // Remove shortcode from buffer
 4541                edits.push((
 4542                    emoji_shortcode_start..selection.start,
 4543                    "".to_string().into(),
 4544                ));
 4545                new_selections.push((
 4546                    Selection {
 4547                        id: selection.id,
 4548                        start: snapshot.anchor_after(emoji_shortcode_start),
 4549                        end: snapshot.anchor_before(selection.start),
 4550                        reversed: selection.reversed,
 4551                        goal: selection.goal,
 4552                    },
 4553                    0,
 4554                ));
 4555
 4556                // Insert emoji
 4557                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4558                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4559                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4560
 4561                continue;
 4562            }
 4563
 4564            // If not handling any auto-close operation, then just replace the selected
 4565            // text with the given input and move the selection to the end of the
 4566            // newly inserted text.
 4567            let anchor = snapshot.anchor_after(selection.end);
 4568            if !self.linked_edit_ranges.is_empty() {
 4569                let start_anchor = snapshot.anchor_before(selection.start);
 4570
 4571                let is_word_char = text.chars().next().is_none_or(|char| {
 4572                    let classifier = snapshot
 4573                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4574                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4575                    classifier.is_word(char)
 4576                });
 4577
 4578                if is_word_char {
 4579                    if let Some(ranges) = self
 4580                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4581                    {
 4582                        for (buffer, edits) in ranges {
 4583                            linked_edits
 4584                                .entry(buffer.clone())
 4585                                .or_default()
 4586                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4587                        }
 4588                    }
 4589                } else {
 4590                    clear_linked_edit_ranges = true;
 4591                }
 4592            }
 4593
 4594            new_selections.push((selection.map(|_| anchor), 0));
 4595            edits.push((selection.start..selection.end, text.clone()));
 4596        }
 4597
 4598        drop(snapshot);
 4599
 4600        self.transact(window, cx, |this, window, cx| {
 4601            if clear_linked_edit_ranges {
 4602                this.linked_edit_ranges.clear();
 4603            }
 4604            let initial_buffer_versions =
 4605                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4606
 4607            this.buffer.update(cx, |buffer, cx| {
 4608                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4609            });
 4610            for (buffer, edits) in linked_edits {
 4611                buffer.update(cx, |buffer, cx| {
 4612                    let snapshot = buffer.snapshot();
 4613                    let edits = edits
 4614                        .into_iter()
 4615                        .map(|(range, text)| {
 4616                            use text::ToPoint as TP;
 4617                            let end_point = TP::to_point(&range.end, &snapshot);
 4618                            let start_point = TP::to_point(&range.start, &snapshot);
 4619                            (start_point..end_point, text)
 4620                        })
 4621                        .sorted_by_key(|(range, _)| range.start);
 4622                    buffer.edit(edits, None, cx);
 4623                })
 4624            }
 4625            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4626            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4627            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4628            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4629                new_anchor_selections,
 4630                &map,
 4631            )
 4632            .zip(new_selection_deltas)
 4633            .map(|(selection, delta)| Selection {
 4634                id: selection.id,
 4635                start: selection.start + delta,
 4636                end: selection.end + delta,
 4637                reversed: selection.reversed,
 4638                goal: SelectionGoal::None,
 4639            })
 4640            .collect::<Vec<_>>();
 4641
 4642            let mut i = 0;
 4643            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4644                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4645                let start = map.buffer_snapshot().anchor_before(position);
 4646                let end = map.buffer_snapshot().anchor_after(position);
 4647                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4648                    match existing_state
 4649                        .range
 4650                        .start
 4651                        .cmp(&start, map.buffer_snapshot())
 4652                    {
 4653                        Ordering::Less => i += 1,
 4654                        Ordering::Greater => break,
 4655                        Ordering::Equal => {
 4656                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4657                                Ordering::Less => i += 1,
 4658                                Ordering::Equal => break,
 4659                                Ordering::Greater => break,
 4660                            }
 4661                        }
 4662                    }
 4663                }
 4664                this.autoclose_regions.insert(
 4665                    i,
 4666                    AutocloseRegion {
 4667                        selection_id,
 4668                        range: start..end,
 4669                        pair,
 4670                    },
 4671                );
 4672            }
 4673
 4674            let had_active_edit_prediction = this.has_active_edit_prediction();
 4675            this.change_selections(
 4676                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4677                window,
 4678                cx,
 4679                |s| s.select(new_selections),
 4680            );
 4681
 4682            if !bracket_inserted
 4683                && let Some(on_type_format_task) =
 4684                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4685            {
 4686                on_type_format_task.detach_and_log_err(cx);
 4687            }
 4688
 4689            let editor_settings = EditorSettings::get_global(cx);
 4690            if bracket_inserted
 4691                && (editor_settings.auto_signature_help
 4692                    || editor_settings.show_signature_help_after_edits)
 4693            {
 4694                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4695            }
 4696
 4697            let trigger_in_words =
 4698                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4699            if this.hard_wrap.is_some() {
 4700                let latest: Range<Point> = this.selections.newest(&map).range();
 4701                if latest.is_empty()
 4702                    && this
 4703                        .buffer()
 4704                        .read(cx)
 4705                        .snapshot(cx)
 4706                        .line_len(MultiBufferRow(latest.start.row))
 4707                        == latest.start.column
 4708                {
 4709                    this.rewrap_impl(
 4710                        RewrapOptions {
 4711                            override_language_settings: true,
 4712                            preserve_existing_whitespace: true,
 4713                        },
 4714                        cx,
 4715                    )
 4716                }
 4717            }
 4718            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4719            refresh_linked_ranges(this, window, cx);
 4720            this.refresh_edit_prediction(true, false, window, cx);
 4721            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4722        });
 4723    }
 4724
 4725    fn find_possible_emoji_shortcode_at_position(
 4726        snapshot: &MultiBufferSnapshot,
 4727        position: Point,
 4728    ) -> Option<String> {
 4729        let mut chars = Vec::new();
 4730        let mut found_colon = false;
 4731        for char in snapshot.reversed_chars_at(position).take(100) {
 4732            // Found a possible emoji shortcode in the middle of the buffer
 4733            if found_colon {
 4734                if char.is_whitespace() {
 4735                    chars.reverse();
 4736                    return Some(chars.iter().collect());
 4737                }
 4738                // If the previous character is not a whitespace, we are in the middle of a word
 4739                // and we only want to complete the shortcode if the word is made up of other emojis
 4740                let mut containing_word = String::new();
 4741                for ch in snapshot
 4742                    .reversed_chars_at(position)
 4743                    .skip(chars.len() + 1)
 4744                    .take(100)
 4745                {
 4746                    if ch.is_whitespace() {
 4747                        break;
 4748                    }
 4749                    containing_word.push(ch);
 4750                }
 4751                let containing_word = containing_word.chars().rev().collect::<String>();
 4752                if util::word_consists_of_emojis(containing_word.as_str()) {
 4753                    chars.reverse();
 4754                    return Some(chars.iter().collect());
 4755                }
 4756            }
 4757
 4758            if char.is_whitespace() || !char.is_ascii() {
 4759                return None;
 4760            }
 4761            if char == ':' {
 4762                found_colon = true;
 4763            } else {
 4764                chars.push(char);
 4765            }
 4766        }
 4767        // Found a possible emoji shortcode at the beginning of the buffer
 4768        chars.reverse();
 4769        Some(chars.iter().collect())
 4770    }
 4771
 4772    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4773        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4774        self.transact(window, cx, |this, window, cx| {
 4775            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4776                let selections = this
 4777                    .selections
 4778                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4779                let multi_buffer = this.buffer.read(cx);
 4780                let buffer = multi_buffer.snapshot(cx);
 4781                selections
 4782                    .iter()
 4783                    .map(|selection| {
 4784                        let start_point = selection.start.to_point(&buffer);
 4785                        let mut existing_indent =
 4786                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4787                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4788                        let start = selection.start;
 4789                        let end = selection.end;
 4790                        let selection_is_empty = start == end;
 4791                        let language_scope = buffer.language_scope_at(start);
 4792                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 4793                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 4794                                &buffer,
 4795                                start..end,
 4796                                language,
 4797                            )
 4798                                || NewlineConfig::insert_extra_newline_tree_sitter(
 4799                                    &buffer,
 4800                                    start..end,
 4801                                );
 4802
 4803                            let mut newline_config = NewlineConfig::Newline {
 4804                                additional_indent: IndentSize::spaces(0),
 4805                                extra_line_additional_indent: if needs_extra_newline {
 4806                                    Some(IndentSize::spaces(0))
 4807                                } else {
 4808                                    None
 4809                                },
 4810                                prevent_auto_indent: false,
 4811                            };
 4812
 4813                            let comment_delimiter = maybe!({
 4814                                if !selection_is_empty {
 4815                                    return None;
 4816                                }
 4817
 4818                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4819                                    return None;
 4820                                }
 4821
 4822                                return comment_delimiter_for_newline(
 4823                                    &start_point,
 4824                                    &buffer,
 4825                                    language,
 4826                                );
 4827                            });
 4828
 4829                            let doc_delimiter = maybe!({
 4830                                if !selection_is_empty {
 4831                                    return None;
 4832                                }
 4833
 4834                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4835                                    return None;
 4836                                }
 4837
 4838                                return documentation_delimiter_for_newline(
 4839                                    &start_point,
 4840                                    &buffer,
 4841                                    language,
 4842                                    &mut newline_config,
 4843                                );
 4844                            });
 4845
 4846                            let list_delimiter = maybe!({
 4847                                if !selection_is_empty {
 4848                                    return None;
 4849                                }
 4850
 4851                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 4852                                    return None;
 4853                                }
 4854
 4855                                return list_delimiter_for_newline(
 4856                                    &start_point,
 4857                                    &buffer,
 4858                                    language,
 4859                                    &mut newline_config,
 4860                                );
 4861                            });
 4862
 4863                            (
 4864                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 4865                                newline_config,
 4866                            )
 4867                        } else {
 4868                            (
 4869                                None,
 4870                                NewlineConfig::Newline {
 4871                                    additional_indent: IndentSize::spaces(0),
 4872                                    extra_line_additional_indent: None,
 4873                                    prevent_auto_indent: false,
 4874                                },
 4875                            )
 4876                        };
 4877
 4878                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 4879                            NewlineConfig::ClearCurrentLine => {
 4880                                let row_start =
 4881                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 4882                                (row_start, String::new(), false)
 4883                            }
 4884                            NewlineConfig::UnindentCurrentLine { continuation } => {
 4885                                let row_start =
 4886                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 4887                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 4888                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 4889                                let reduced_indent =
 4890                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 4891                                let mut new_text = String::new();
 4892                                new_text.extend(reduced_indent.chars());
 4893                                new_text.push_str(continuation);
 4894                                (row_start, new_text, true)
 4895                            }
 4896                            NewlineConfig::Newline {
 4897                                additional_indent,
 4898                                extra_line_additional_indent,
 4899                                prevent_auto_indent,
 4900                            } => {
 4901                                let capacity_for_delimiter =
 4902                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 4903                                let extra_line_len = extra_line_additional_indent
 4904                                    .map(|i| 1 + existing_indent.len as usize + i.len as usize)
 4905                                    .unwrap_or(0);
 4906                                let mut new_text = String::with_capacity(
 4907                                    1 + capacity_for_delimiter
 4908                                        + existing_indent.len as usize
 4909                                        + additional_indent.len as usize
 4910                                        + extra_line_len,
 4911                                );
 4912                                new_text.push('\n');
 4913                                new_text.extend(existing_indent.chars());
 4914                                new_text.extend(additional_indent.chars());
 4915                                if let Some(delimiter) = &delimiter {
 4916                                    new_text.push_str(delimiter);
 4917                                }
 4918                                if let Some(extra_indent) = extra_line_additional_indent {
 4919                                    new_text.push('\n');
 4920                                    new_text.extend(existing_indent.chars());
 4921                                    new_text.extend(extra_indent.chars());
 4922                                }
 4923                                (start, new_text, *prevent_auto_indent)
 4924                            }
 4925                        };
 4926
 4927                        let anchor = buffer.anchor_after(end);
 4928                        let new_selection = selection.map(|_| anchor);
 4929                        (
 4930                            ((edit_start..end, new_text), prevent_auto_indent),
 4931                            (newline_config.has_extra_line(), new_selection),
 4932                        )
 4933                    })
 4934                    .unzip()
 4935            };
 4936
 4937            let mut auto_indent_edits = Vec::new();
 4938            let mut edits = Vec::new();
 4939            for (edit, prevent_auto_indent) in edits_with_flags {
 4940                if prevent_auto_indent {
 4941                    edits.push(edit);
 4942                } else {
 4943                    auto_indent_edits.push(edit);
 4944                }
 4945            }
 4946            if !edits.is_empty() {
 4947                this.edit(edits, cx);
 4948            }
 4949            if !auto_indent_edits.is_empty() {
 4950                this.edit_with_autoindent(auto_indent_edits, cx);
 4951            }
 4952
 4953            let buffer = this.buffer.read(cx).snapshot(cx);
 4954            let new_selections = selection_info
 4955                .into_iter()
 4956                .map(|(extra_newline_inserted, new_selection)| {
 4957                    let mut cursor = new_selection.end.to_point(&buffer);
 4958                    if extra_newline_inserted {
 4959                        cursor.row -= 1;
 4960                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4961                    }
 4962                    new_selection.map(|_| cursor)
 4963                })
 4964                .collect();
 4965
 4966            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4967            this.refresh_edit_prediction(true, false, window, cx);
 4968            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 4969                task.detach_and_log_err(cx);
 4970            }
 4971        });
 4972    }
 4973
 4974    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4975        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4976
 4977        let buffer = self.buffer.read(cx);
 4978        let snapshot = buffer.snapshot(cx);
 4979
 4980        let mut edits = Vec::new();
 4981        let mut rows = Vec::new();
 4982
 4983        for (rows_inserted, selection) in self
 4984            .selections
 4985            .all_adjusted(&self.display_snapshot(cx))
 4986            .into_iter()
 4987            .enumerate()
 4988        {
 4989            let cursor = selection.head();
 4990            let row = cursor.row;
 4991
 4992            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4993
 4994            let newline = "\n".to_string();
 4995            edits.push((start_of_line..start_of_line, newline));
 4996
 4997            rows.push(row + rows_inserted as u32);
 4998        }
 4999
 5000        self.transact(window, cx, |editor, window, cx| {
 5001            editor.edit(edits, cx);
 5002
 5003            editor.change_selections(Default::default(), window, cx, |s| {
 5004                let mut index = 0;
 5005                s.move_cursors_with(|map, _, _| {
 5006                    let row = rows[index];
 5007                    index += 1;
 5008
 5009                    let point = Point::new(row, 0);
 5010                    let boundary = map.next_line_boundary(point).1;
 5011                    let clipped = map.clip_point(boundary, Bias::Left);
 5012
 5013                    (clipped, SelectionGoal::None)
 5014                });
 5015            });
 5016
 5017            let mut indent_edits = Vec::new();
 5018            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5019            for row in rows {
 5020                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5021                for (row, indent) in indents {
 5022                    if indent.len == 0 {
 5023                        continue;
 5024                    }
 5025
 5026                    let text = match indent.kind {
 5027                        IndentKind::Space => " ".repeat(indent.len as usize),
 5028                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5029                    };
 5030                    let point = Point::new(row.0, 0);
 5031                    indent_edits.push((point..point, text));
 5032                }
 5033            }
 5034            editor.edit(indent_edits, cx);
 5035            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5036                format.detach_and_log_err(cx);
 5037            }
 5038        });
 5039    }
 5040
 5041    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5042        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5043
 5044        let buffer = self.buffer.read(cx);
 5045        let snapshot = buffer.snapshot(cx);
 5046
 5047        let mut edits = Vec::new();
 5048        let mut rows = Vec::new();
 5049        let mut rows_inserted = 0;
 5050
 5051        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5052            let cursor = selection.head();
 5053            let row = cursor.row;
 5054
 5055            let point = Point::new(row + 1, 0);
 5056            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5057
 5058            let newline = "\n".to_string();
 5059            edits.push((start_of_line..start_of_line, newline));
 5060
 5061            rows_inserted += 1;
 5062            rows.push(row + rows_inserted);
 5063        }
 5064
 5065        self.transact(window, cx, |editor, window, cx| {
 5066            editor.edit(edits, cx);
 5067
 5068            editor.change_selections(Default::default(), window, cx, |s| {
 5069                let mut index = 0;
 5070                s.move_cursors_with(|map, _, _| {
 5071                    let row = rows[index];
 5072                    index += 1;
 5073
 5074                    let point = Point::new(row, 0);
 5075                    let boundary = map.next_line_boundary(point).1;
 5076                    let clipped = map.clip_point(boundary, Bias::Left);
 5077
 5078                    (clipped, SelectionGoal::None)
 5079                });
 5080            });
 5081
 5082            let mut indent_edits = Vec::new();
 5083            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5084            for row in rows {
 5085                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5086                for (row, indent) in indents {
 5087                    if indent.len == 0 {
 5088                        continue;
 5089                    }
 5090
 5091                    let text = match indent.kind {
 5092                        IndentKind::Space => " ".repeat(indent.len as usize),
 5093                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5094                    };
 5095                    let point = Point::new(row.0, 0);
 5096                    indent_edits.push((point..point, text));
 5097                }
 5098            }
 5099            editor.edit(indent_edits, cx);
 5100            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5101                format.detach_and_log_err(cx);
 5102            }
 5103        });
 5104    }
 5105
 5106    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5107        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5108            original_indent_columns: Vec::new(),
 5109        });
 5110        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5111    }
 5112
 5113    fn insert_with_autoindent_mode(
 5114        &mut self,
 5115        text: &str,
 5116        autoindent_mode: Option<AutoindentMode>,
 5117        window: &mut Window,
 5118        cx: &mut Context<Self>,
 5119    ) {
 5120        if self.read_only(cx) {
 5121            return;
 5122        }
 5123
 5124        let text: Arc<str> = text.into();
 5125        self.transact(window, cx, |this, window, cx| {
 5126            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5127            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5128                let anchors = {
 5129                    let snapshot = buffer.read(cx);
 5130                    old_selections
 5131                        .iter()
 5132                        .map(|s| {
 5133                            let anchor = snapshot.anchor_after(s.head());
 5134                            s.map(|_| anchor)
 5135                        })
 5136                        .collect::<Vec<_>>()
 5137                };
 5138                buffer.edit(
 5139                    old_selections
 5140                        .iter()
 5141                        .map(|s| (s.start..s.end, text.clone())),
 5142                    autoindent_mode,
 5143                    cx,
 5144                );
 5145                anchors
 5146            });
 5147
 5148            this.change_selections(Default::default(), window, cx, |s| {
 5149                s.select_anchors(selection_anchors);
 5150            });
 5151
 5152            cx.notify();
 5153        });
 5154    }
 5155
 5156    fn trigger_completion_on_input(
 5157        &mut self,
 5158        text: &str,
 5159        trigger_in_words: bool,
 5160        window: &mut Window,
 5161        cx: &mut Context<Self>,
 5162    ) {
 5163        let completions_source = self
 5164            .context_menu
 5165            .borrow()
 5166            .as_ref()
 5167            .and_then(|menu| match menu {
 5168                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5169                CodeContextMenu::CodeActions(_) => None,
 5170            });
 5171
 5172        match completions_source {
 5173            Some(CompletionsMenuSource::Words { .. }) => {
 5174                self.open_or_update_completions_menu(
 5175                    Some(CompletionsMenuSource::Words {
 5176                        ignore_threshold: false,
 5177                    }),
 5178                    None,
 5179                    trigger_in_words,
 5180                    window,
 5181                    cx,
 5182                );
 5183            }
 5184            _ => self.open_or_update_completions_menu(
 5185                None,
 5186                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5187                true,
 5188                window,
 5189                cx,
 5190            ),
 5191        }
 5192    }
 5193
 5194    /// If any empty selections is touching the start of its innermost containing autoclose
 5195    /// region, expand it to select the brackets.
 5196    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5197        let selections = self
 5198            .selections
 5199            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5200        let buffer = self.buffer.read(cx).read(cx);
 5201        let new_selections = self
 5202            .selections_with_autoclose_regions(selections, &buffer)
 5203            .map(|(mut selection, region)| {
 5204                if !selection.is_empty() {
 5205                    return selection;
 5206                }
 5207
 5208                if let Some(region) = region {
 5209                    let mut range = region.range.to_offset(&buffer);
 5210                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5211                        range.start -= region.pair.start.len();
 5212                        if buffer.contains_str_at(range.start, &region.pair.start)
 5213                            && buffer.contains_str_at(range.end, &region.pair.end)
 5214                        {
 5215                            range.end += region.pair.end.len();
 5216                            selection.start = range.start;
 5217                            selection.end = range.end;
 5218
 5219                            return selection;
 5220                        }
 5221                    }
 5222                }
 5223
 5224                let always_treat_brackets_as_autoclosed = buffer
 5225                    .language_settings_at(selection.start, cx)
 5226                    .always_treat_brackets_as_autoclosed;
 5227
 5228                if !always_treat_brackets_as_autoclosed {
 5229                    return selection;
 5230                }
 5231
 5232                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5233                    for (pair, enabled) in scope.brackets() {
 5234                        if !enabled || !pair.close {
 5235                            continue;
 5236                        }
 5237
 5238                        if buffer.contains_str_at(selection.start, &pair.end) {
 5239                            let pair_start_len = pair.start.len();
 5240                            if buffer.contains_str_at(
 5241                                selection.start.saturating_sub_usize(pair_start_len),
 5242                                &pair.start,
 5243                            ) {
 5244                                selection.start -= pair_start_len;
 5245                                selection.end += pair.end.len();
 5246
 5247                                return selection;
 5248                            }
 5249                        }
 5250                    }
 5251                }
 5252
 5253                selection
 5254            })
 5255            .collect();
 5256
 5257        drop(buffer);
 5258        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5259            selections.select(new_selections)
 5260        });
 5261    }
 5262
 5263    /// Iterate the given selections, and for each one, find the smallest surrounding
 5264    /// autoclose region. This uses the ordering of the selections and the autoclose
 5265    /// regions to avoid repeated comparisons.
 5266    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5267        &'a self,
 5268        selections: impl IntoIterator<Item = Selection<D>>,
 5269        buffer: &'a MultiBufferSnapshot,
 5270    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5271        let mut i = 0;
 5272        let mut regions = self.autoclose_regions.as_slice();
 5273        selections.into_iter().map(move |selection| {
 5274            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5275
 5276            let mut enclosing = None;
 5277            while let Some(pair_state) = regions.get(i) {
 5278                if pair_state.range.end.to_offset(buffer) < range.start {
 5279                    regions = &regions[i + 1..];
 5280                    i = 0;
 5281                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5282                    break;
 5283                } else {
 5284                    if pair_state.selection_id == selection.id {
 5285                        enclosing = Some(pair_state);
 5286                    }
 5287                    i += 1;
 5288                }
 5289            }
 5290
 5291            (selection, enclosing)
 5292        })
 5293    }
 5294
 5295    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5296    fn invalidate_autoclose_regions(
 5297        &mut self,
 5298        mut selections: &[Selection<Anchor>],
 5299        buffer: &MultiBufferSnapshot,
 5300    ) {
 5301        self.autoclose_regions.retain(|state| {
 5302            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5303                return false;
 5304            }
 5305
 5306            let mut i = 0;
 5307            while let Some(selection) = selections.get(i) {
 5308                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5309                    selections = &selections[1..];
 5310                    continue;
 5311                }
 5312                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5313                    break;
 5314                }
 5315                if selection.id == state.selection_id {
 5316                    return true;
 5317                } else {
 5318                    i += 1;
 5319                }
 5320            }
 5321            false
 5322        });
 5323    }
 5324
 5325    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5326        let offset = position.to_offset(buffer);
 5327        let (word_range, kind) =
 5328            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5329        if offset > word_range.start && kind == Some(CharKind::Word) {
 5330            Some(
 5331                buffer
 5332                    .text_for_range(word_range.start..offset)
 5333                    .collect::<String>(),
 5334            )
 5335        } else {
 5336            None
 5337        }
 5338    }
 5339
 5340    pub fn visible_excerpts(
 5341        &self,
 5342        lsp_related_only: bool,
 5343        cx: &mut Context<Editor>,
 5344    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5345        let project = self.project().cloned();
 5346        let multi_buffer = self.buffer().read(cx);
 5347        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5348        let multi_buffer_visible_start = self
 5349            .scroll_manager
 5350            .anchor()
 5351            .anchor
 5352            .to_point(&multi_buffer_snapshot);
 5353        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5354            multi_buffer_visible_start
 5355                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5356            Bias::Left,
 5357        );
 5358        multi_buffer_snapshot
 5359            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5360            .into_iter()
 5361            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5362            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5363                if !lsp_related_only {
 5364                    return Some((
 5365                        excerpt_id,
 5366                        (
 5367                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5368                            buffer.version().clone(),
 5369                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5370                        ),
 5371                    ));
 5372                }
 5373
 5374                let project = project.as_ref()?.read(cx);
 5375                let buffer_file = project::File::from_dyn(buffer.file())?;
 5376                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5377                let worktree_entry = buffer_worktree
 5378                    .read(cx)
 5379                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5380                if worktree_entry.is_ignored {
 5381                    None
 5382                } else {
 5383                    Some((
 5384                        excerpt_id,
 5385                        (
 5386                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5387                            buffer.version().clone(),
 5388                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5389                        ),
 5390                    ))
 5391                }
 5392            })
 5393            .collect()
 5394    }
 5395
 5396    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5397        TextLayoutDetails {
 5398            text_system: window.text_system().clone(),
 5399            editor_style: self.style.clone().unwrap(),
 5400            rem_size: window.rem_size(),
 5401            scroll_anchor: self.scroll_manager.anchor(),
 5402            visible_rows: self.visible_line_count(),
 5403            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5404        }
 5405    }
 5406
 5407    fn trigger_on_type_formatting(
 5408        &self,
 5409        input: String,
 5410        window: &mut Window,
 5411        cx: &mut Context<Self>,
 5412    ) -> Option<Task<Result<()>>> {
 5413        if input.chars().count() != 1 {
 5414            return None;
 5415        }
 5416
 5417        let project = self.project()?;
 5418        let position = self.selections.newest_anchor().head();
 5419        let (buffer, buffer_position) = self
 5420            .buffer
 5421            .read(cx)
 5422            .text_anchor_for_position(position, cx)?;
 5423
 5424        let settings = language_settings::language_settings(
 5425            buffer
 5426                .read(cx)
 5427                .language_at(buffer_position)
 5428                .map(|l| l.name()),
 5429            buffer.read(cx).file(),
 5430            cx,
 5431        );
 5432        if !settings.use_on_type_format {
 5433            return None;
 5434        }
 5435
 5436        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5437        // hence we do LSP request & edit on host side only — add formats to host's history.
 5438        let push_to_lsp_host_history = true;
 5439        // If this is not the host, append its history with new edits.
 5440        let push_to_client_history = project.read(cx).is_via_collab();
 5441
 5442        let on_type_formatting = project.update(cx, |project, cx| {
 5443            project.on_type_format(
 5444                buffer.clone(),
 5445                buffer_position,
 5446                input,
 5447                push_to_lsp_host_history,
 5448                cx,
 5449            )
 5450        });
 5451        Some(cx.spawn_in(window, async move |editor, cx| {
 5452            if let Some(transaction) = on_type_formatting.await? {
 5453                if push_to_client_history {
 5454                    buffer
 5455                        .update(cx, |buffer, _| {
 5456                            buffer.push_transaction(transaction, Instant::now());
 5457                            buffer.finalize_last_transaction();
 5458                        })
 5459                        .ok();
 5460                }
 5461                editor.update(cx, |editor, cx| {
 5462                    editor.refresh_document_highlights(cx);
 5463                })?;
 5464            }
 5465            Ok(())
 5466        }))
 5467    }
 5468
 5469    pub fn show_word_completions(
 5470        &mut self,
 5471        _: &ShowWordCompletions,
 5472        window: &mut Window,
 5473        cx: &mut Context<Self>,
 5474    ) {
 5475        self.open_or_update_completions_menu(
 5476            Some(CompletionsMenuSource::Words {
 5477                ignore_threshold: true,
 5478            }),
 5479            None,
 5480            false,
 5481            window,
 5482            cx,
 5483        );
 5484    }
 5485
 5486    pub fn show_completions(
 5487        &mut self,
 5488        _: &ShowCompletions,
 5489        window: &mut Window,
 5490        cx: &mut Context<Self>,
 5491    ) {
 5492        self.open_or_update_completions_menu(None, None, false, window, cx);
 5493    }
 5494
 5495    fn open_or_update_completions_menu(
 5496        &mut self,
 5497        requested_source: Option<CompletionsMenuSource>,
 5498        trigger: Option<String>,
 5499        trigger_in_words: bool,
 5500        window: &mut Window,
 5501        cx: &mut Context<Self>,
 5502    ) {
 5503        if self.pending_rename.is_some() {
 5504            return;
 5505        }
 5506
 5507        let completions_source = self
 5508            .context_menu
 5509            .borrow()
 5510            .as_ref()
 5511            .and_then(|menu| match menu {
 5512                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5513                CodeContextMenu::CodeActions(_) => None,
 5514            });
 5515
 5516        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5517
 5518        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5519        // inserted and selected. To handle that case, the start of the selection is used so that
 5520        // the menu starts with all choices.
 5521        let position = self
 5522            .selections
 5523            .newest_anchor()
 5524            .start
 5525            .bias_right(&multibuffer_snapshot);
 5526        if position.diff_base_anchor.is_some() {
 5527            return;
 5528        }
 5529        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5530        let Some(buffer) = buffer_position
 5531            .text_anchor
 5532            .buffer_id
 5533            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5534        else {
 5535            return;
 5536        };
 5537        let buffer_snapshot = buffer.read(cx).snapshot();
 5538
 5539        let menu_is_open = matches!(
 5540            self.context_menu.borrow().as_ref(),
 5541            Some(CodeContextMenu::Completions(_))
 5542        );
 5543
 5544        let language = buffer_snapshot
 5545            .language_at(buffer_position.text_anchor)
 5546            .map(|language| language.name());
 5547
 5548        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5549        let completion_settings = language_settings.completions.clone();
 5550
 5551        let show_completions_on_input = self
 5552            .show_completions_on_input_override
 5553            .unwrap_or(language_settings.show_completions_on_input);
 5554        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5555            return;
 5556        }
 5557
 5558        let query: Option<Arc<String>> =
 5559            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5560                .map(|query| query.into());
 5561
 5562        drop(multibuffer_snapshot);
 5563
 5564        // Hide the current completions menu when query is empty. Without this, cached
 5565        // completions from before the trigger char may be reused (#32774).
 5566        if query.is_none() && menu_is_open {
 5567            self.hide_context_menu(window, cx);
 5568        }
 5569
 5570        let mut ignore_word_threshold = false;
 5571        let provider = match requested_source {
 5572            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5573            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5574                ignore_word_threshold = ignore_threshold;
 5575                None
 5576            }
 5577            Some(CompletionsMenuSource::SnippetChoices)
 5578            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5579                log::error!("bug: SnippetChoices requested_source is not handled");
 5580                None
 5581            }
 5582        };
 5583
 5584        let sort_completions = provider
 5585            .as_ref()
 5586            .is_some_and(|provider| provider.sort_completions());
 5587
 5588        let filter_completions = provider
 5589            .as_ref()
 5590            .is_none_or(|provider| provider.filter_completions());
 5591
 5592        let was_snippets_only = matches!(
 5593            completions_source,
 5594            Some(CompletionsMenuSource::SnippetsOnly)
 5595        );
 5596
 5597        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5598            if filter_completions {
 5599                menu.filter(
 5600                    query.clone().unwrap_or_default(),
 5601                    buffer_position.text_anchor,
 5602                    &buffer,
 5603                    provider.clone(),
 5604                    window,
 5605                    cx,
 5606                );
 5607            }
 5608            // When `is_incomplete` is false, no need to re-query completions when the current query
 5609            // is a suffix of the initial query.
 5610            let was_complete = !menu.is_incomplete;
 5611            if was_complete && !was_snippets_only {
 5612                // If the new query is a suffix of the old query (typing more characters) and
 5613                // the previous result was complete, the existing completions can be filtered.
 5614                //
 5615                // Note that snippet completions are always complete.
 5616                let query_matches = match (&menu.initial_query, &query) {
 5617                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5618                    (None, _) => true,
 5619                    _ => false,
 5620                };
 5621                if query_matches {
 5622                    let position_matches = if menu.initial_position == position {
 5623                        true
 5624                    } else {
 5625                        let snapshot = self.buffer.read(cx).read(cx);
 5626                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5627                    };
 5628                    if position_matches {
 5629                        return;
 5630                    }
 5631                }
 5632            }
 5633        };
 5634
 5635        let Anchor {
 5636            excerpt_id: buffer_excerpt_id,
 5637            text_anchor: buffer_position,
 5638            ..
 5639        } = buffer_position;
 5640
 5641        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5642            buffer_snapshot.surrounding_word(buffer_position, None)
 5643        {
 5644            let word_to_exclude = buffer_snapshot
 5645                .text_for_range(word_range.clone())
 5646                .collect::<String>();
 5647            (
 5648                buffer_snapshot.anchor_before(word_range.start)
 5649                    ..buffer_snapshot.anchor_after(buffer_position),
 5650                Some(word_to_exclude),
 5651            )
 5652        } else {
 5653            (buffer_position..buffer_position, None)
 5654        };
 5655
 5656        let show_completion_documentation = buffer_snapshot
 5657            .settings_at(buffer_position, cx)
 5658            .show_completion_documentation;
 5659
 5660        // The document can be large, so stay in reasonable bounds when searching for words,
 5661        // otherwise completion pop-up might be slow to appear.
 5662        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5663        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5664        let min_word_search = buffer_snapshot.clip_point(
 5665            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5666            Bias::Left,
 5667        );
 5668        let max_word_search = buffer_snapshot.clip_point(
 5669            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5670            Bias::Right,
 5671        );
 5672        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5673            ..buffer_snapshot.point_to_offset(max_word_search);
 5674
 5675        let skip_digits = query
 5676            .as_ref()
 5677            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5678
 5679        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5680            trigger.as_ref().is_none_or(|trigger| {
 5681                provider.is_completion_trigger(
 5682                    &buffer,
 5683                    position.text_anchor,
 5684                    trigger,
 5685                    trigger_in_words,
 5686                    cx,
 5687                )
 5688            })
 5689        });
 5690
 5691        let provider_responses = if let Some(provider) = &provider
 5692            && load_provider_completions
 5693        {
 5694            let trigger_character =
 5695                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5696            let completion_context = CompletionContext {
 5697                trigger_kind: match &trigger_character {
 5698                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5699                    None => CompletionTriggerKind::INVOKED,
 5700                },
 5701                trigger_character,
 5702            };
 5703
 5704            provider.completions(
 5705                buffer_excerpt_id,
 5706                &buffer,
 5707                buffer_position,
 5708                completion_context,
 5709                window,
 5710                cx,
 5711            )
 5712        } else {
 5713            Task::ready(Ok(Vec::new()))
 5714        };
 5715
 5716        let load_word_completions = if !self.word_completions_enabled {
 5717            false
 5718        } else if requested_source
 5719            == Some(CompletionsMenuSource::Words {
 5720                ignore_threshold: true,
 5721            })
 5722        {
 5723            true
 5724        } else {
 5725            load_provider_completions
 5726                && completion_settings.words != WordsCompletionMode::Disabled
 5727                && (ignore_word_threshold || {
 5728                    let words_min_length = completion_settings.words_min_length;
 5729                    // check whether word has at least `words_min_length` characters
 5730                    let query_chars = query.iter().flat_map(|q| q.chars());
 5731                    query_chars.take(words_min_length).count() == words_min_length
 5732                })
 5733        };
 5734
 5735        let mut words = if load_word_completions {
 5736            cx.background_spawn({
 5737                let buffer_snapshot = buffer_snapshot.clone();
 5738                async move {
 5739                    buffer_snapshot.words_in_range(WordsQuery {
 5740                        fuzzy_contents: None,
 5741                        range: word_search_range,
 5742                        skip_digits,
 5743                    })
 5744                }
 5745            })
 5746        } else {
 5747            Task::ready(BTreeMap::default())
 5748        };
 5749
 5750        let snippets = if let Some(provider) = &provider
 5751            && provider.show_snippets()
 5752            && let Some(project) = self.project()
 5753        {
 5754            let char_classifier = buffer_snapshot
 5755                .char_classifier_at(buffer_position)
 5756                .scope_context(Some(CharScopeContext::Completion));
 5757            project.update(cx, |project, cx| {
 5758                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5759            })
 5760        } else {
 5761            Task::ready(Ok(CompletionResponse {
 5762                completions: Vec::new(),
 5763                display_options: Default::default(),
 5764                is_incomplete: false,
 5765            }))
 5766        };
 5767
 5768        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5769
 5770        let id = post_inc(&mut self.next_completion_id);
 5771        let task = cx.spawn_in(window, async move |editor, cx| {
 5772            let Ok(()) = editor.update(cx, |this, _| {
 5773                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5774            }) else {
 5775                return;
 5776            };
 5777
 5778            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5779            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5780            let mut completions = Vec::new();
 5781            let mut is_incomplete = false;
 5782            let mut display_options: Option<CompletionDisplayOptions> = None;
 5783            if let Some(provider_responses) = provider_responses.await.log_err()
 5784                && !provider_responses.is_empty()
 5785            {
 5786                for response in provider_responses {
 5787                    completions.extend(response.completions);
 5788                    is_incomplete = is_incomplete || response.is_incomplete;
 5789                    match display_options.as_mut() {
 5790                        None => {
 5791                            display_options = Some(response.display_options);
 5792                        }
 5793                        Some(options) => options.merge(&response.display_options),
 5794                    }
 5795                }
 5796                if completion_settings.words == WordsCompletionMode::Fallback {
 5797                    words = Task::ready(BTreeMap::default());
 5798                }
 5799            }
 5800            let display_options = display_options.unwrap_or_default();
 5801
 5802            let mut words = words.await;
 5803            if let Some(word_to_exclude) = &word_to_exclude {
 5804                words.remove(word_to_exclude);
 5805            }
 5806            for lsp_completion in &completions {
 5807                words.remove(&lsp_completion.new_text);
 5808            }
 5809            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5810                replace_range: word_replace_range.clone(),
 5811                new_text: word.clone(),
 5812                label: CodeLabel::plain(word, None),
 5813                match_start: None,
 5814                snippet_deduplication_key: None,
 5815                icon_path: None,
 5816                documentation: None,
 5817                source: CompletionSource::BufferWord {
 5818                    word_range,
 5819                    resolved: false,
 5820                },
 5821                insert_text_mode: Some(InsertTextMode::AS_IS),
 5822                confirm: None,
 5823            }));
 5824
 5825            completions.extend(
 5826                snippets
 5827                    .await
 5828                    .into_iter()
 5829                    .flat_map(|response| response.completions),
 5830            );
 5831
 5832            let menu = if completions.is_empty() {
 5833                None
 5834            } else {
 5835                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5836                    let languages = editor
 5837                        .workspace
 5838                        .as_ref()
 5839                        .and_then(|(workspace, _)| workspace.upgrade())
 5840                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5841                    let menu = CompletionsMenu::new(
 5842                        id,
 5843                        requested_source.unwrap_or(if load_provider_completions {
 5844                            CompletionsMenuSource::Normal
 5845                        } else {
 5846                            CompletionsMenuSource::SnippetsOnly
 5847                        }),
 5848                        sort_completions,
 5849                        show_completion_documentation,
 5850                        position,
 5851                        query.clone(),
 5852                        is_incomplete,
 5853                        buffer.clone(),
 5854                        completions.into(),
 5855                        editor
 5856                            .context_menu()
 5857                            .borrow_mut()
 5858                            .as_ref()
 5859                            .map(|menu| menu.primary_scroll_handle()),
 5860                        display_options,
 5861                        snippet_sort_order,
 5862                        languages,
 5863                        language,
 5864                        cx,
 5865                    );
 5866
 5867                    let query = if filter_completions { query } else { None };
 5868                    let matches_task = menu.do_async_filtering(
 5869                        query.unwrap_or_default(),
 5870                        buffer_position,
 5871                        &buffer,
 5872                        cx,
 5873                    );
 5874                    (menu, matches_task)
 5875                }) else {
 5876                    return;
 5877                };
 5878
 5879                let matches = matches_task.await;
 5880
 5881                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5882                    // Newer menu already set, so exit.
 5883                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5884                        editor.context_menu.borrow().as_ref()
 5885                        && prev_menu.id > id
 5886                    {
 5887                        return;
 5888                    };
 5889
 5890                    // Only valid to take prev_menu because either the new menu is immediately set
 5891                    // below, or the menu is hidden.
 5892                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5893                        editor.context_menu.borrow_mut().take()
 5894                    {
 5895                        let position_matches =
 5896                            if prev_menu.initial_position == menu.initial_position {
 5897                                true
 5898                            } else {
 5899                                let snapshot = editor.buffer.read(cx).read(cx);
 5900                                prev_menu.initial_position.to_offset(&snapshot)
 5901                                    == menu.initial_position.to_offset(&snapshot)
 5902                            };
 5903                        if position_matches {
 5904                            // Preserve markdown cache before `set_filter_results` because it will
 5905                            // try to populate the documentation cache.
 5906                            menu.preserve_markdown_cache(prev_menu);
 5907                        }
 5908                    };
 5909
 5910                    menu.set_filter_results(matches, provider, window, cx);
 5911                }) else {
 5912                    return;
 5913                };
 5914
 5915                menu.visible().then_some(menu)
 5916            };
 5917
 5918            editor
 5919                .update_in(cx, |editor, window, cx| {
 5920                    if editor.focus_handle.is_focused(window)
 5921                        && let Some(menu) = menu
 5922                    {
 5923                        *editor.context_menu.borrow_mut() =
 5924                            Some(CodeContextMenu::Completions(menu));
 5925
 5926                        crate::hover_popover::hide_hover(editor, cx);
 5927                        if editor.show_edit_predictions_in_menu() {
 5928                            editor.update_visible_edit_prediction(window, cx);
 5929                        } else {
 5930                            editor.discard_edit_prediction(false, cx);
 5931                        }
 5932
 5933                        cx.notify();
 5934                        return;
 5935                    }
 5936
 5937                    if editor.completion_tasks.len() <= 1 {
 5938                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5939                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5940                        // If it was already hidden and we don't show edit predictions in the menu,
 5941                        // we should also show the edit prediction when available.
 5942                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5943                            editor.update_visible_edit_prediction(window, cx);
 5944                        }
 5945                    }
 5946                })
 5947                .ok();
 5948        });
 5949
 5950        self.completion_tasks.push((id, task));
 5951    }
 5952
 5953    #[cfg(feature = "test-support")]
 5954    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5955        let menu = self.context_menu.borrow();
 5956        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5957            let completions = menu.completions.borrow();
 5958            Some(completions.to_vec())
 5959        } else {
 5960            None
 5961        }
 5962    }
 5963
 5964    pub fn with_completions_menu_matching_id<R>(
 5965        &self,
 5966        id: CompletionId,
 5967        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5968    ) -> R {
 5969        let mut context_menu = self.context_menu.borrow_mut();
 5970        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5971            return f(None);
 5972        };
 5973        if completions_menu.id != id {
 5974            return f(None);
 5975        }
 5976        f(Some(completions_menu))
 5977    }
 5978
 5979    pub fn confirm_completion(
 5980        &mut self,
 5981        action: &ConfirmCompletion,
 5982        window: &mut Window,
 5983        cx: &mut Context<Self>,
 5984    ) -> Option<Task<Result<()>>> {
 5985        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5986        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5987    }
 5988
 5989    pub fn confirm_completion_insert(
 5990        &mut self,
 5991        _: &ConfirmCompletionInsert,
 5992        window: &mut Window,
 5993        cx: &mut Context<Self>,
 5994    ) -> Option<Task<Result<()>>> {
 5995        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5996        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5997    }
 5998
 5999    pub fn confirm_completion_replace(
 6000        &mut self,
 6001        _: &ConfirmCompletionReplace,
 6002        window: &mut Window,
 6003        cx: &mut Context<Self>,
 6004    ) -> Option<Task<Result<()>>> {
 6005        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6006        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6007    }
 6008
 6009    pub fn compose_completion(
 6010        &mut self,
 6011        action: &ComposeCompletion,
 6012        window: &mut Window,
 6013        cx: &mut Context<Self>,
 6014    ) -> Option<Task<Result<()>>> {
 6015        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6016        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6017    }
 6018
 6019    fn do_completion(
 6020        &mut self,
 6021        item_ix: Option<usize>,
 6022        intent: CompletionIntent,
 6023        window: &mut Window,
 6024        cx: &mut Context<Editor>,
 6025    ) -> Option<Task<Result<()>>> {
 6026        use language::ToOffset as _;
 6027
 6028        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6029        else {
 6030            return None;
 6031        };
 6032
 6033        let candidate_id = {
 6034            let entries = completions_menu.entries.borrow();
 6035            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6036            if self.show_edit_predictions_in_menu() {
 6037                self.discard_edit_prediction(true, cx);
 6038            }
 6039            mat.candidate_id
 6040        };
 6041
 6042        let completion = completions_menu
 6043            .completions
 6044            .borrow()
 6045            .get(candidate_id)?
 6046            .clone();
 6047        cx.stop_propagation();
 6048
 6049        let buffer_handle = completions_menu.buffer.clone();
 6050
 6051        let CompletionEdit {
 6052            new_text,
 6053            snippet,
 6054            replace_range,
 6055        } = process_completion_for_edit(
 6056            &completion,
 6057            intent,
 6058            &buffer_handle,
 6059            &completions_menu.initial_position.text_anchor,
 6060            cx,
 6061        );
 6062
 6063        let buffer = buffer_handle.read(cx);
 6064        let snapshot = self.buffer.read(cx).snapshot(cx);
 6065        let newest_anchor = self.selections.newest_anchor();
 6066        let replace_range_multibuffer = {
 6067            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6068            excerpt.map_range_from_buffer(replace_range.clone())
 6069        };
 6070        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6071            return None;
 6072        }
 6073
 6074        let old_text = buffer
 6075            .text_for_range(replace_range.clone())
 6076            .collect::<String>();
 6077        let lookbehind = newest_anchor
 6078            .start
 6079            .text_anchor
 6080            .to_offset(buffer)
 6081            .saturating_sub(replace_range.start.0);
 6082        let lookahead = replace_range
 6083            .end
 6084            .0
 6085            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6086        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6087        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6088
 6089        let selections = self
 6090            .selections
 6091            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6092        let mut ranges = Vec::new();
 6093        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6094
 6095        for selection in &selections {
 6096            let range = if selection.id == newest_anchor.id {
 6097                replace_range_multibuffer.clone()
 6098            } else {
 6099                let mut range = selection.range();
 6100
 6101                // if prefix is present, don't duplicate it
 6102                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6103                    range.start = range.start.saturating_sub_usize(lookbehind);
 6104
 6105                    // if suffix is also present, mimic the newest cursor and replace it
 6106                    if selection.id != newest_anchor.id
 6107                        && snapshot.contains_str_at(range.end, suffix)
 6108                    {
 6109                        range.end += lookahead;
 6110                    }
 6111                }
 6112                range
 6113            };
 6114
 6115            ranges.push(range.clone());
 6116
 6117            if !self.linked_edit_ranges.is_empty() {
 6118                let start_anchor = snapshot.anchor_before(range.start);
 6119                let end_anchor = snapshot.anchor_after(range.end);
 6120                if let Some(ranges) = self
 6121                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6122                {
 6123                    for (buffer, edits) in ranges {
 6124                        linked_edits
 6125                            .entry(buffer.clone())
 6126                            .or_default()
 6127                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6128                    }
 6129                }
 6130            }
 6131        }
 6132
 6133        let common_prefix_len = old_text
 6134            .chars()
 6135            .zip(new_text.chars())
 6136            .take_while(|(a, b)| a == b)
 6137            .map(|(a, _)| a.len_utf8())
 6138            .sum::<usize>();
 6139
 6140        cx.emit(EditorEvent::InputHandled {
 6141            utf16_range_to_replace: None,
 6142            text: new_text[common_prefix_len..].into(),
 6143        });
 6144
 6145        self.transact(window, cx, |editor, window, cx| {
 6146            if let Some(mut snippet) = snippet {
 6147                snippet.text = new_text.to_string();
 6148                editor
 6149                    .insert_snippet(&ranges, snippet, window, cx)
 6150                    .log_err();
 6151            } else {
 6152                editor.buffer.update(cx, |multi_buffer, cx| {
 6153                    let auto_indent = match completion.insert_text_mode {
 6154                        Some(InsertTextMode::AS_IS) => None,
 6155                        _ => editor.autoindent_mode.clone(),
 6156                    };
 6157                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6158                    multi_buffer.edit(edits, auto_indent, cx);
 6159                });
 6160            }
 6161            for (buffer, edits) in linked_edits {
 6162                buffer.update(cx, |buffer, cx| {
 6163                    let snapshot = buffer.snapshot();
 6164                    let edits = edits
 6165                        .into_iter()
 6166                        .map(|(range, text)| {
 6167                            use text::ToPoint as TP;
 6168                            let end_point = TP::to_point(&range.end, &snapshot);
 6169                            let start_point = TP::to_point(&range.start, &snapshot);
 6170                            (start_point..end_point, text)
 6171                        })
 6172                        .sorted_by_key(|(range, _)| range.start);
 6173                    buffer.edit(edits, None, cx);
 6174                })
 6175            }
 6176
 6177            editor.refresh_edit_prediction(true, false, window, cx);
 6178        });
 6179        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6180
 6181        let show_new_completions_on_confirm = completion
 6182            .confirm
 6183            .as_ref()
 6184            .is_some_and(|confirm| confirm(intent, window, cx));
 6185        if show_new_completions_on_confirm {
 6186            self.open_or_update_completions_menu(None, None, false, window, cx);
 6187        }
 6188
 6189        let provider = self.completion_provider.as_ref()?;
 6190
 6191        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6192        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6193            let CompletionSource::Lsp {
 6194                lsp_completion,
 6195                server_id,
 6196                ..
 6197            } = &completion.source
 6198            else {
 6199                return None;
 6200            };
 6201            let lsp_command = lsp_completion.command.as_ref()?;
 6202            let available_commands = lsp_store
 6203                .read(cx)
 6204                .lsp_server_capabilities
 6205                .get(server_id)
 6206                .and_then(|server_capabilities| {
 6207                    server_capabilities
 6208                        .execute_command_provider
 6209                        .as_ref()
 6210                        .map(|options| options.commands.as_slice())
 6211                })?;
 6212            if available_commands.contains(&lsp_command.command) {
 6213                Some(CodeAction {
 6214                    server_id: *server_id,
 6215                    range: language::Anchor::MIN..language::Anchor::MIN,
 6216                    lsp_action: LspAction::Command(lsp_command.clone()),
 6217                    resolved: false,
 6218                })
 6219            } else {
 6220                None
 6221            }
 6222        });
 6223
 6224        drop(completion);
 6225        let apply_edits = provider.apply_additional_edits_for_completion(
 6226            buffer_handle.clone(),
 6227            completions_menu.completions.clone(),
 6228            candidate_id,
 6229            true,
 6230            cx,
 6231        );
 6232
 6233        let editor_settings = EditorSettings::get_global(cx);
 6234        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6235            // After the code completion is finished, users often want to know what signatures are needed.
 6236            // so we should automatically call signature_help
 6237            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6238        }
 6239
 6240        Some(cx.spawn_in(window, async move |editor, cx| {
 6241            apply_edits.await?;
 6242
 6243            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6244                let title = command.lsp_action.title().to_owned();
 6245                let project_transaction = lsp_store
 6246                    .update(cx, |lsp_store, cx| {
 6247                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6248                    })?
 6249                    .await
 6250                    .context("applying post-completion command")?;
 6251                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6252                    Self::open_project_transaction(
 6253                        &editor,
 6254                        workspace.downgrade(),
 6255                        project_transaction,
 6256                        title,
 6257                        cx,
 6258                    )
 6259                    .await?;
 6260                }
 6261            }
 6262
 6263            Ok(())
 6264        }))
 6265    }
 6266
 6267    pub fn toggle_code_actions(
 6268        &mut self,
 6269        action: &ToggleCodeActions,
 6270        window: &mut Window,
 6271        cx: &mut Context<Self>,
 6272    ) {
 6273        let quick_launch = action.quick_launch;
 6274        let mut context_menu = self.context_menu.borrow_mut();
 6275        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6276            if code_actions.deployed_from == action.deployed_from {
 6277                // Toggle if we're selecting the same one
 6278                *context_menu = None;
 6279                cx.notify();
 6280                return;
 6281            } else {
 6282                // Otherwise, clear it and start a new one
 6283                *context_menu = None;
 6284                cx.notify();
 6285            }
 6286        }
 6287        drop(context_menu);
 6288        let snapshot = self.snapshot(window, cx);
 6289        let deployed_from = action.deployed_from.clone();
 6290        let action = action.clone();
 6291        self.completion_tasks.clear();
 6292        self.discard_edit_prediction(false, cx);
 6293
 6294        let multibuffer_point = match &action.deployed_from {
 6295            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6296                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6297            }
 6298            _ => self
 6299                .selections
 6300                .newest::<Point>(&snapshot.display_snapshot)
 6301                .head(),
 6302        };
 6303        let Some((buffer, buffer_row)) = snapshot
 6304            .buffer_snapshot()
 6305            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6306            .and_then(|(buffer_snapshot, range)| {
 6307                self.buffer()
 6308                    .read(cx)
 6309                    .buffer(buffer_snapshot.remote_id())
 6310                    .map(|buffer| (buffer, range.start.row))
 6311            })
 6312        else {
 6313            return;
 6314        };
 6315        let buffer_id = buffer.read(cx).remote_id();
 6316        let tasks = self
 6317            .tasks
 6318            .get(&(buffer_id, buffer_row))
 6319            .map(|t| Arc::new(t.to_owned()));
 6320
 6321        if !self.focus_handle.is_focused(window) {
 6322            return;
 6323        }
 6324        let project = self.project.clone();
 6325
 6326        let code_actions_task = match deployed_from {
 6327            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6328            _ => self.code_actions(buffer_row, window, cx),
 6329        };
 6330
 6331        let runnable_task = match deployed_from {
 6332            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6333            _ => {
 6334                let mut task_context_task = Task::ready(None);
 6335                if let Some(tasks) = &tasks
 6336                    && let Some(project) = project
 6337                {
 6338                    task_context_task =
 6339                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6340                }
 6341
 6342                cx.spawn_in(window, {
 6343                    let buffer = buffer.clone();
 6344                    async move |editor, cx| {
 6345                        let task_context = task_context_task.await;
 6346
 6347                        let resolved_tasks =
 6348                            tasks
 6349                                .zip(task_context.clone())
 6350                                .map(|(tasks, task_context)| ResolvedTasks {
 6351                                    templates: tasks.resolve(&task_context).collect(),
 6352                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6353                                        multibuffer_point.row,
 6354                                        tasks.column,
 6355                                    )),
 6356                                });
 6357                        let debug_scenarios = editor
 6358                            .update(cx, |editor, cx| {
 6359                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6360                            })?
 6361                            .await;
 6362                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6363                    }
 6364                })
 6365            }
 6366        };
 6367
 6368        cx.spawn_in(window, async move |editor, cx| {
 6369            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6370            let code_actions = code_actions_task.await;
 6371            let spawn_straight_away = quick_launch
 6372                && resolved_tasks
 6373                    .as_ref()
 6374                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6375                && code_actions
 6376                    .as_ref()
 6377                    .is_none_or(|actions| actions.is_empty())
 6378                && debug_scenarios.is_empty();
 6379
 6380            editor.update_in(cx, |editor, window, cx| {
 6381                crate::hover_popover::hide_hover(editor, cx);
 6382                let actions = CodeActionContents::new(
 6383                    resolved_tasks,
 6384                    code_actions,
 6385                    debug_scenarios,
 6386                    task_context.unwrap_or_default(),
 6387                );
 6388
 6389                // Don't show the menu if there are no actions available
 6390                if actions.is_empty() {
 6391                    cx.notify();
 6392                    return Task::ready(Ok(()));
 6393                }
 6394
 6395                *editor.context_menu.borrow_mut() =
 6396                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6397                        buffer,
 6398                        actions,
 6399                        selected_item: Default::default(),
 6400                        scroll_handle: UniformListScrollHandle::default(),
 6401                        deployed_from,
 6402                    }));
 6403                cx.notify();
 6404                if spawn_straight_away
 6405                    && let Some(task) = editor.confirm_code_action(
 6406                        &ConfirmCodeAction { item_ix: Some(0) },
 6407                        window,
 6408                        cx,
 6409                    )
 6410                {
 6411                    return task;
 6412                }
 6413
 6414                Task::ready(Ok(()))
 6415            })
 6416        })
 6417        .detach_and_log_err(cx);
 6418    }
 6419
 6420    fn debug_scenarios(
 6421        &mut self,
 6422        resolved_tasks: &Option<ResolvedTasks>,
 6423        buffer: &Entity<Buffer>,
 6424        cx: &mut App,
 6425    ) -> Task<Vec<task::DebugScenario>> {
 6426        maybe!({
 6427            let project = self.project()?;
 6428            let dap_store = project.read(cx).dap_store();
 6429            let mut scenarios = vec![];
 6430            let resolved_tasks = resolved_tasks.as_ref()?;
 6431            let buffer = buffer.read(cx);
 6432            let language = buffer.language()?;
 6433            let file = buffer.file();
 6434            let debug_adapter = language_settings(language.name().into(), file, cx)
 6435                .debuggers
 6436                .first()
 6437                .map(SharedString::from)
 6438                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6439
 6440            dap_store.update(cx, |dap_store, cx| {
 6441                for (_, task) in &resolved_tasks.templates {
 6442                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6443                        task.original_task().clone(),
 6444                        debug_adapter.clone().into(),
 6445                        task.display_label().to_owned().into(),
 6446                        cx,
 6447                    );
 6448                    scenarios.push(maybe_scenario);
 6449                }
 6450            });
 6451            Some(cx.background_spawn(async move {
 6452                futures::future::join_all(scenarios)
 6453                    .await
 6454                    .into_iter()
 6455                    .flatten()
 6456                    .collect::<Vec<_>>()
 6457            }))
 6458        })
 6459        .unwrap_or_else(|| Task::ready(vec![]))
 6460    }
 6461
 6462    fn code_actions(
 6463        &mut self,
 6464        buffer_row: u32,
 6465        window: &mut Window,
 6466        cx: &mut Context<Self>,
 6467    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6468        let mut task = self.code_actions_task.take();
 6469        cx.spawn_in(window, async move |editor, cx| {
 6470            while let Some(prev_task) = task {
 6471                prev_task.await.log_err();
 6472                task = editor
 6473                    .update(cx, |this, _| this.code_actions_task.take())
 6474                    .ok()?;
 6475            }
 6476
 6477            editor
 6478                .update(cx, |editor, cx| {
 6479                    editor
 6480                        .available_code_actions
 6481                        .clone()
 6482                        .and_then(|(location, code_actions)| {
 6483                            let snapshot = location.buffer.read(cx).snapshot();
 6484                            let point_range = location.range.to_point(&snapshot);
 6485                            let point_range = point_range.start.row..=point_range.end.row;
 6486                            if point_range.contains(&buffer_row) {
 6487                                Some(code_actions)
 6488                            } else {
 6489                                None
 6490                            }
 6491                        })
 6492                })
 6493                .ok()
 6494                .flatten()
 6495        })
 6496    }
 6497
 6498    pub fn confirm_code_action(
 6499        &mut self,
 6500        action: &ConfirmCodeAction,
 6501        window: &mut Window,
 6502        cx: &mut Context<Self>,
 6503    ) -> Option<Task<Result<()>>> {
 6504        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6505
 6506        let actions_menu =
 6507            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6508                menu
 6509            } else {
 6510                return None;
 6511            };
 6512
 6513        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6514        let action = actions_menu.actions.get(action_ix)?;
 6515        let title = action.label();
 6516        let buffer = actions_menu.buffer;
 6517        let workspace = self.workspace()?;
 6518
 6519        match action {
 6520            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6521                workspace.update(cx, |workspace, cx| {
 6522                    workspace.schedule_resolved_task(
 6523                        task_source_kind,
 6524                        resolved_task,
 6525                        false,
 6526                        window,
 6527                        cx,
 6528                    );
 6529
 6530                    Some(Task::ready(Ok(())))
 6531                })
 6532            }
 6533            CodeActionsItem::CodeAction {
 6534                excerpt_id,
 6535                action,
 6536                provider,
 6537            } => {
 6538                let apply_code_action =
 6539                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6540                let workspace = workspace.downgrade();
 6541                Some(cx.spawn_in(window, async move |editor, cx| {
 6542                    let project_transaction = apply_code_action.await?;
 6543                    Self::open_project_transaction(
 6544                        &editor,
 6545                        workspace,
 6546                        project_transaction,
 6547                        title,
 6548                        cx,
 6549                    )
 6550                    .await
 6551                }))
 6552            }
 6553            CodeActionsItem::DebugScenario(scenario) => {
 6554                let context = actions_menu.actions.context;
 6555
 6556                workspace.update(cx, |workspace, cx| {
 6557                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6558                    workspace.start_debug_session(
 6559                        scenario,
 6560                        context,
 6561                        Some(buffer),
 6562                        None,
 6563                        window,
 6564                        cx,
 6565                    );
 6566                });
 6567                Some(Task::ready(Ok(())))
 6568            }
 6569        }
 6570    }
 6571
 6572    fn open_transaction_for_hidden_buffers(
 6573        workspace: Entity<Workspace>,
 6574        transaction: ProjectTransaction,
 6575        title: String,
 6576        window: &mut Window,
 6577        cx: &mut Context<Self>,
 6578    ) {
 6579        if transaction.0.is_empty() {
 6580            return;
 6581        }
 6582
 6583        let edited_buffers_already_open = {
 6584            let other_editors: Vec<Entity<Editor>> = workspace
 6585                .read(cx)
 6586                .panes()
 6587                .iter()
 6588                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6589                .filter(|editor| editor.entity_id() != cx.entity_id())
 6590                .collect();
 6591
 6592            transaction.0.keys().all(|buffer| {
 6593                other_editors.iter().any(|editor| {
 6594                    let multi_buffer = editor.read(cx).buffer();
 6595                    multi_buffer.read(cx).is_singleton()
 6596                        && multi_buffer
 6597                            .read(cx)
 6598                            .as_singleton()
 6599                            .map_or(false, |singleton| {
 6600                                singleton.entity_id() == buffer.entity_id()
 6601                            })
 6602                })
 6603            })
 6604        };
 6605        if !edited_buffers_already_open {
 6606            let workspace = workspace.downgrade();
 6607            cx.defer_in(window, move |_, window, cx| {
 6608                cx.spawn_in(window, async move |editor, cx| {
 6609                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6610                        .await
 6611                        .ok()
 6612                })
 6613                .detach();
 6614            });
 6615        }
 6616    }
 6617
 6618    pub async fn open_project_transaction(
 6619        editor: &WeakEntity<Editor>,
 6620        workspace: WeakEntity<Workspace>,
 6621        transaction: ProjectTransaction,
 6622        title: String,
 6623        cx: &mut AsyncWindowContext,
 6624    ) -> Result<()> {
 6625        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6626        cx.update(|_, cx| {
 6627            entries.sort_unstable_by_key(|(buffer, _)| {
 6628                buffer.read(cx).file().map(|f| f.path().clone())
 6629            });
 6630        })?;
 6631        if entries.is_empty() {
 6632            return Ok(());
 6633        }
 6634
 6635        // If the project transaction's edits are all contained within this editor, then
 6636        // avoid opening a new editor to display them.
 6637
 6638        if let [(buffer, transaction)] = &*entries {
 6639            let excerpt = editor.update(cx, |editor, cx| {
 6640                editor
 6641                    .buffer()
 6642                    .read(cx)
 6643                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6644            })?;
 6645            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6646                && excerpted_buffer == *buffer
 6647            {
 6648                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6649                    let excerpt_range = excerpt_range.to_offset(buffer);
 6650                    buffer
 6651                        .edited_ranges_for_transaction::<usize>(transaction)
 6652                        .all(|range| {
 6653                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6654                        })
 6655                })?;
 6656
 6657                if all_edits_within_excerpt {
 6658                    return Ok(());
 6659                }
 6660            }
 6661        }
 6662
 6663        let mut ranges_to_highlight = Vec::new();
 6664        let excerpt_buffer = cx.new(|cx| {
 6665            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6666            for (buffer_handle, transaction) in &entries {
 6667                let edited_ranges = buffer_handle
 6668                    .read(cx)
 6669                    .edited_ranges_for_transaction::<Point>(transaction)
 6670                    .collect::<Vec<_>>();
 6671                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6672                    PathKey::for_buffer(buffer_handle, cx),
 6673                    buffer_handle.clone(),
 6674                    edited_ranges,
 6675                    multibuffer_context_lines(cx),
 6676                    cx,
 6677                );
 6678
 6679                ranges_to_highlight.extend(ranges);
 6680            }
 6681            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6682            multibuffer
 6683        })?;
 6684
 6685        workspace.update_in(cx, |workspace, window, cx| {
 6686            let project = workspace.project().clone();
 6687            let editor =
 6688                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6689            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6690            editor.update(cx, |editor, cx| {
 6691                editor.highlight_background::<Self>(
 6692                    &ranges_to_highlight,
 6693                    |_, theme| theme.colors().editor_highlighted_line_background,
 6694                    cx,
 6695                );
 6696            });
 6697        })?;
 6698
 6699        Ok(())
 6700    }
 6701
 6702    pub fn clear_code_action_providers(&mut self) {
 6703        self.code_action_providers.clear();
 6704        self.available_code_actions.take();
 6705    }
 6706
 6707    pub fn add_code_action_provider(
 6708        &mut self,
 6709        provider: Rc<dyn CodeActionProvider>,
 6710        window: &mut Window,
 6711        cx: &mut Context<Self>,
 6712    ) {
 6713        if self
 6714            .code_action_providers
 6715            .iter()
 6716            .any(|existing_provider| existing_provider.id() == provider.id())
 6717        {
 6718            return;
 6719        }
 6720
 6721        self.code_action_providers.push(provider);
 6722        self.refresh_code_actions(window, cx);
 6723    }
 6724
 6725    pub fn remove_code_action_provider(
 6726        &mut self,
 6727        id: Arc<str>,
 6728        window: &mut Window,
 6729        cx: &mut Context<Self>,
 6730    ) {
 6731        self.code_action_providers
 6732            .retain(|provider| provider.id() != id);
 6733        self.refresh_code_actions(window, cx);
 6734    }
 6735
 6736    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6737        !self.code_action_providers.is_empty()
 6738            && EditorSettings::get_global(cx).toolbar.code_actions
 6739    }
 6740
 6741    pub fn has_available_code_actions(&self) -> bool {
 6742        self.available_code_actions
 6743            .as_ref()
 6744            .is_some_and(|(_, actions)| !actions.is_empty())
 6745    }
 6746
 6747    fn render_inline_code_actions(
 6748        &self,
 6749        icon_size: ui::IconSize,
 6750        display_row: DisplayRow,
 6751        is_active: bool,
 6752        cx: &mut Context<Self>,
 6753    ) -> AnyElement {
 6754        let show_tooltip = !self.context_menu_visible();
 6755        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6756            .icon_size(icon_size)
 6757            .shape(ui::IconButtonShape::Square)
 6758            .icon_color(ui::Color::Hidden)
 6759            .toggle_state(is_active)
 6760            .when(show_tooltip, |this| {
 6761                this.tooltip({
 6762                    let focus_handle = self.focus_handle.clone();
 6763                    move |_window, cx| {
 6764                        Tooltip::for_action_in(
 6765                            "Toggle Code Actions",
 6766                            &ToggleCodeActions {
 6767                                deployed_from: None,
 6768                                quick_launch: false,
 6769                            },
 6770                            &focus_handle,
 6771                            cx,
 6772                        )
 6773                    }
 6774                })
 6775            })
 6776            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6777                window.focus(&editor.focus_handle(cx), cx);
 6778                editor.toggle_code_actions(
 6779                    &crate::actions::ToggleCodeActions {
 6780                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6781                            display_row,
 6782                        )),
 6783                        quick_launch: false,
 6784                    },
 6785                    window,
 6786                    cx,
 6787                );
 6788            }))
 6789            .into_any_element()
 6790    }
 6791
 6792    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6793        &self.context_menu
 6794    }
 6795
 6796    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6797        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6798            cx.background_executor()
 6799                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6800                .await;
 6801
 6802            let (start_buffer, start, _, end, newest_selection) = this
 6803                .update(cx, |this, cx| {
 6804                    let newest_selection = this.selections.newest_anchor().clone();
 6805                    if newest_selection.head().diff_base_anchor.is_some() {
 6806                        return None;
 6807                    }
 6808                    let display_snapshot = this.display_snapshot(cx);
 6809                    let newest_selection_adjusted =
 6810                        this.selections.newest_adjusted(&display_snapshot);
 6811                    let buffer = this.buffer.read(cx);
 6812
 6813                    let (start_buffer, start) =
 6814                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6815                    let (end_buffer, end) =
 6816                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6817
 6818                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6819                })?
 6820                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6821                .context(
 6822                    "Expected selection to lie in a single buffer when refreshing code actions",
 6823                )?;
 6824            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6825                let providers = this.code_action_providers.clone();
 6826                let tasks = this
 6827                    .code_action_providers
 6828                    .iter()
 6829                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6830                    .collect::<Vec<_>>();
 6831                (providers, tasks)
 6832            })?;
 6833
 6834            let mut actions = Vec::new();
 6835            for (provider, provider_actions) in
 6836                providers.into_iter().zip(future::join_all(tasks).await)
 6837            {
 6838                if let Some(provider_actions) = provider_actions.log_err() {
 6839                    actions.extend(provider_actions.into_iter().map(|action| {
 6840                        AvailableCodeAction {
 6841                            excerpt_id: newest_selection.start.excerpt_id,
 6842                            action,
 6843                            provider: provider.clone(),
 6844                        }
 6845                    }));
 6846                }
 6847            }
 6848
 6849            this.update(cx, |this, cx| {
 6850                this.available_code_actions = if actions.is_empty() {
 6851                    None
 6852                } else {
 6853                    Some((
 6854                        Location {
 6855                            buffer: start_buffer,
 6856                            range: start..end,
 6857                        },
 6858                        actions.into(),
 6859                    ))
 6860                };
 6861                cx.notify();
 6862            })
 6863        }));
 6864    }
 6865
 6866    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6867        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6868            self.show_git_blame_inline = false;
 6869
 6870            self.show_git_blame_inline_delay_task =
 6871                Some(cx.spawn_in(window, async move |this, cx| {
 6872                    cx.background_executor().timer(delay).await;
 6873
 6874                    this.update(cx, |this, cx| {
 6875                        this.show_git_blame_inline = true;
 6876                        cx.notify();
 6877                    })
 6878                    .log_err();
 6879                }));
 6880        }
 6881    }
 6882
 6883    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6884        let snapshot = self.snapshot(window, cx);
 6885        let cursor = self
 6886            .selections
 6887            .newest::<Point>(&snapshot.display_snapshot)
 6888            .head();
 6889        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6890        else {
 6891            return;
 6892        };
 6893
 6894        if self.blame.is_none() {
 6895            self.start_git_blame(true, window, cx);
 6896        }
 6897        let Some(blame) = self.blame.as_ref() else {
 6898            return;
 6899        };
 6900
 6901        let row_info = RowInfo {
 6902            buffer_id: Some(buffer.remote_id()),
 6903            buffer_row: Some(point.row),
 6904            ..Default::default()
 6905        };
 6906        let Some((buffer, blame_entry)) = blame
 6907            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6908            .flatten()
 6909        else {
 6910            return;
 6911        };
 6912
 6913        let anchor = self.selections.newest_anchor().head();
 6914        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 6915        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6916            self.show_blame_popover(
 6917                buffer,
 6918                &blame_entry,
 6919                position + last_bounds.origin,
 6920                true,
 6921                cx,
 6922            );
 6923        };
 6924    }
 6925
 6926    fn show_blame_popover(
 6927        &mut self,
 6928        buffer: BufferId,
 6929        blame_entry: &BlameEntry,
 6930        position: gpui::Point<Pixels>,
 6931        ignore_timeout: bool,
 6932        cx: &mut Context<Self>,
 6933    ) {
 6934        if let Some(state) = &mut self.inline_blame_popover {
 6935            state.hide_task.take();
 6936        } else {
 6937            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6938            let blame_entry = blame_entry.clone();
 6939            let show_task = cx.spawn(async move |editor, cx| {
 6940                if !ignore_timeout {
 6941                    cx.background_executor()
 6942                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6943                        .await;
 6944                }
 6945                editor
 6946                    .update(cx, |editor, cx| {
 6947                        editor.inline_blame_popover_show_task.take();
 6948                        let Some(blame) = editor.blame.as_ref() else {
 6949                            return;
 6950                        };
 6951                        let blame = blame.read(cx);
 6952                        let details = blame.details_for_entry(buffer, &blame_entry);
 6953                        let markdown = cx.new(|cx| {
 6954                            Markdown::new(
 6955                                details
 6956                                    .as_ref()
 6957                                    .map(|message| message.message.clone())
 6958                                    .unwrap_or_default(),
 6959                                None,
 6960                                None,
 6961                                cx,
 6962                            )
 6963                        });
 6964                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6965                            position,
 6966                            hide_task: None,
 6967                            popover_bounds: None,
 6968                            popover_state: InlineBlamePopoverState {
 6969                                scroll_handle: ScrollHandle::new(),
 6970                                commit_message: details,
 6971                                markdown,
 6972                            },
 6973                            keyboard_grace: ignore_timeout,
 6974                        });
 6975                        cx.notify();
 6976                    })
 6977                    .ok();
 6978            });
 6979            self.inline_blame_popover_show_task = Some(show_task);
 6980        }
 6981    }
 6982
 6983    pub fn has_mouse_context_menu(&self) -> bool {
 6984        self.mouse_context_menu.is_some()
 6985    }
 6986
 6987    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6988        self.inline_blame_popover_show_task.take();
 6989        if let Some(state) = &mut self.inline_blame_popover {
 6990            let hide_task = cx.spawn(async move |editor, cx| {
 6991                if !ignore_timeout {
 6992                    cx.background_executor()
 6993                        .timer(std::time::Duration::from_millis(100))
 6994                        .await;
 6995                }
 6996                editor
 6997                    .update(cx, |editor, cx| {
 6998                        editor.inline_blame_popover.take();
 6999                        cx.notify();
 7000                    })
 7001                    .ok();
 7002            });
 7003            state.hide_task = Some(hide_task);
 7004            true
 7005        } else {
 7006            false
 7007        }
 7008    }
 7009
 7010    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7011        if self.pending_rename.is_some() {
 7012            return None;
 7013        }
 7014
 7015        let provider = self.semantics_provider.clone()?;
 7016        let buffer = self.buffer.read(cx);
 7017        let newest_selection = self.selections.newest_anchor().clone();
 7018        let cursor_position = newest_selection.head();
 7019        let (cursor_buffer, cursor_buffer_position) =
 7020            buffer.text_anchor_for_position(cursor_position, cx)?;
 7021        let (tail_buffer, tail_buffer_position) =
 7022            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7023        if cursor_buffer != tail_buffer {
 7024            return None;
 7025        }
 7026
 7027        let snapshot = cursor_buffer.read(cx).snapshot();
 7028        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7029        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7030        if start_word_range != end_word_range {
 7031            self.document_highlights_task.take();
 7032            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7033            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7034            return None;
 7035        }
 7036
 7037        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7038        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7039            cx.background_executor()
 7040                .timer(Duration::from_millis(debounce))
 7041                .await;
 7042
 7043            let highlights = if let Some(highlights) = cx
 7044                .update(|cx| {
 7045                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7046                })
 7047                .ok()
 7048                .flatten()
 7049            {
 7050                highlights.await.log_err()
 7051            } else {
 7052                None
 7053            };
 7054
 7055            if let Some(highlights) = highlights {
 7056                this.update(cx, |this, cx| {
 7057                    if this.pending_rename.is_some() {
 7058                        return;
 7059                    }
 7060
 7061                    let buffer = this.buffer.read(cx);
 7062                    if buffer
 7063                        .text_anchor_for_position(cursor_position, cx)
 7064                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7065                    {
 7066                        return;
 7067                    }
 7068
 7069                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7070                    let mut write_ranges = Vec::new();
 7071                    let mut read_ranges = Vec::new();
 7072                    for highlight in highlights {
 7073                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7074                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7075                        {
 7076                            let start = highlight
 7077                                .range
 7078                                .start
 7079                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7080                            let end = highlight
 7081                                .range
 7082                                .end
 7083                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7084                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7085                                continue;
 7086                            }
 7087
 7088                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7089                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7090                                write_ranges.push(range);
 7091                            } else {
 7092                                read_ranges.push(range);
 7093                            }
 7094                        }
 7095                    }
 7096
 7097                    this.highlight_background::<DocumentHighlightRead>(
 7098                        &read_ranges,
 7099                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7100                        cx,
 7101                    );
 7102                    this.highlight_background::<DocumentHighlightWrite>(
 7103                        &write_ranges,
 7104                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7105                        cx,
 7106                    );
 7107                    cx.notify();
 7108                })
 7109                .log_err();
 7110            }
 7111        }));
 7112        None
 7113    }
 7114
 7115    fn prepare_highlight_query_from_selection(
 7116        &mut self,
 7117        window: &Window,
 7118        cx: &mut Context<Editor>,
 7119    ) -> Option<(String, Range<Anchor>)> {
 7120        if matches!(self.mode, EditorMode::SingleLine) {
 7121            return None;
 7122        }
 7123        if !EditorSettings::get_global(cx).selection_highlight {
 7124            return None;
 7125        }
 7126        if self.selections.count() != 1 || self.selections.line_mode() {
 7127            return None;
 7128        }
 7129        let snapshot = self.snapshot(window, cx);
 7130        let selection = self.selections.newest::<Point>(&snapshot);
 7131        // If the selection spans multiple rows OR it is empty
 7132        if selection.start.row != selection.end.row
 7133            || selection.start.column == selection.end.column
 7134        {
 7135            return None;
 7136        }
 7137        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7138        let query = snapshot
 7139            .buffer_snapshot()
 7140            .text_for_range(selection_anchor_range.clone())
 7141            .collect::<String>();
 7142        if query.trim().is_empty() {
 7143            return None;
 7144        }
 7145        Some((query, selection_anchor_range))
 7146    }
 7147
 7148    #[ztracing::instrument(skip_all)]
 7149    fn update_selection_occurrence_highlights(
 7150        &mut self,
 7151        query_text: String,
 7152        query_range: Range<Anchor>,
 7153        multi_buffer_range_to_query: Range<Point>,
 7154        use_debounce: bool,
 7155        window: &mut Window,
 7156        cx: &mut Context<Editor>,
 7157    ) -> Task<()> {
 7158        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7159        cx.spawn_in(window, async move |editor, cx| {
 7160            if use_debounce {
 7161                cx.background_executor()
 7162                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7163                    .await;
 7164            }
 7165            let match_task = cx.background_spawn(async move {
 7166                let buffer_ranges = multi_buffer_snapshot
 7167                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7168                    .into_iter()
 7169                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7170                let mut match_ranges = Vec::new();
 7171                let Ok(regex) = project::search::SearchQuery::text(
 7172                    query_text.clone(),
 7173                    false,
 7174                    false,
 7175                    false,
 7176                    Default::default(),
 7177                    Default::default(),
 7178                    false,
 7179                    None,
 7180                ) else {
 7181                    return Vec::default();
 7182                };
 7183                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7184                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7185                    match_ranges.extend(
 7186                        regex
 7187                            .search(
 7188                                buffer_snapshot,
 7189                                Some(search_range.start.0..search_range.end.0),
 7190                            )
 7191                            .await
 7192                            .into_iter()
 7193                            .filter_map(|match_range| {
 7194                                let match_start = buffer_snapshot
 7195                                    .anchor_after(search_range.start + match_range.start);
 7196                                let match_end = buffer_snapshot
 7197                                    .anchor_before(search_range.start + match_range.end);
 7198                                let match_anchor_range =
 7199                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7200                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7201                            }),
 7202                    );
 7203                }
 7204                match_ranges
 7205            });
 7206            let match_ranges = match_task.await;
 7207            editor
 7208                .update_in(cx, |editor, _, cx| {
 7209                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7210                    if !match_ranges.is_empty() {
 7211                        editor.highlight_background::<SelectedTextHighlight>(
 7212                            &match_ranges,
 7213                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7214                            cx,
 7215                        )
 7216                    }
 7217                })
 7218                .log_err();
 7219        })
 7220    }
 7221
 7222    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7223        struct NewlineFold;
 7224        let type_id = std::any::TypeId::of::<NewlineFold>();
 7225        if !self.mode.is_single_line() {
 7226            return;
 7227        }
 7228        let snapshot = self.snapshot(window, cx);
 7229        if snapshot.buffer_snapshot().max_point().row == 0 {
 7230            return;
 7231        }
 7232        let task = cx.background_spawn(async move {
 7233            let new_newlines = snapshot
 7234                .buffer_chars_at(MultiBufferOffset(0))
 7235                .filter_map(|(c, i)| {
 7236                    if c == '\n' {
 7237                        Some(
 7238                            snapshot.buffer_snapshot().anchor_after(i)
 7239                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7240                        )
 7241                    } else {
 7242                        None
 7243                    }
 7244                })
 7245                .collect::<Vec<_>>();
 7246            let existing_newlines = snapshot
 7247                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7248                .filter_map(|fold| {
 7249                    if fold.placeholder.type_tag == Some(type_id) {
 7250                        Some(fold.range.start..fold.range.end)
 7251                    } else {
 7252                        None
 7253                    }
 7254                })
 7255                .collect::<Vec<_>>();
 7256
 7257            (new_newlines, existing_newlines)
 7258        });
 7259        self.folding_newlines = cx.spawn(async move |this, cx| {
 7260            let (new_newlines, existing_newlines) = task.await;
 7261            if new_newlines == existing_newlines {
 7262                return;
 7263            }
 7264            let placeholder = FoldPlaceholder {
 7265                render: Arc::new(move |_, _, cx| {
 7266                    div()
 7267                        .bg(cx.theme().status().hint_background)
 7268                        .border_b_1()
 7269                        .size_full()
 7270                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7271                        .border_color(cx.theme().status().hint)
 7272                        .child("\\n")
 7273                        .into_any()
 7274                }),
 7275                constrain_width: false,
 7276                merge_adjacent: false,
 7277                type_tag: Some(type_id),
 7278            };
 7279            let creases = new_newlines
 7280                .into_iter()
 7281                .map(|range| Crease::simple(range, placeholder.clone()))
 7282                .collect();
 7283            this.update(cx, |this, cx| {
 7284                this.display_map.update(cx, |display_map, cx| {
 7285                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7286                    display_map.fold(creases, cx);
 7287                });
 7288            })
 7289            .ok();
 7290        });
 7291    }
 7292
 7293    #[ztracing::instrument(skip_all)]
 7294    fn refresh_selected_text_highlights(
 7295        &mut self,
 7296        on_buffer_edit: bool,
 7297        window: &mut Window,
 7298        cx: &mut Context<Editor>,
 7299    ) {
 7300        let Some((query_text, query_range)) =
 7301            self.prepare_highlight_query_from_selection(window, cx)
 7302        else {
 7303            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7304            self.quick_selection_highlight_task.take();
 7305            self.debounced_selection_highlight_task.take();
 7306            return;
 7307        };
 7308        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7309        if on_buffer_edit
 7310            || self
 7311                .quick_selection_highlight_task
 7312                .as_ref()
 7313                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7314        {
 7315            let multi_buffer_visible_start = self
 7316                .scroll_manager
 7317                .anchor()
 7318                .anchor
 7319                .to_point(&multi_buffer_snapshot);
 7320            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7321                multi_buffer_visible_start
 7322                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7323                Bias::Left,
 7324            );
 7325            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7326            self.quick_selection_highlight_task = Some((
 7327                query_range.clone(),
 7328                self.update_selection_occurrence_highlights(
 7329                    query_text.clone(),
 7330                    query_range.clone(),
 7331                    multi_buffer_visible_range,
 7332                    false,
 7333                    window,
 7334                    cx,
 7335                ),
 7336            ));
 7337        }
 7338        if on_buffer_edit
 7339            || self
 7340                .debounced_selection_highlight_task
 7341                .as_ref()
 7342                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7343        {
 7344            let multi_buffer_start = multi_buffer_snapshot
 7345                .anchor_before(MultiBufferOffset(0))
 7346                .to_point(&multi_buffer_snapshot);
 7347            let multi_buffer_end = multi_buffer_snapshot
 7348                .anchor_after(multi_buffer_snapshot.len())
 7349                .to_point(&multi_buffer_snapshot);
 7350            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7351            self.debounced_selection_highlight_task = Some((
 7352                query_range.clone(),
 7353                self.update_selection_occurrence_highlights(
 7354                    query_text,
 7355                    query_range,
 7356                    multi_buffer_full_range,
 7357                    true,
 7358                    window,
 7359                    cx,
 7360                ),
 7361            ));
 7362        }
 7363    }
 7364
 7365    pub fn refresh_edit_prediction(
 7366        &mut self,
 7367        debounce: bool,
 7368        user_requested: bool,
 7369        window: &mut Window,
 7370        cx: &mut Context<Self>,
 7371    ) -> Option<()> {
 7372        if DisableAiSettings::get_global(cx).disable_ai {
 7373            return None;
 7374        }
 7375
 7376        let provider = self.edit_prediction_provider()?;
 7377        let cursor = self.selections.newest_anchor().head();
 7378        let (buffer, cursor_buffer_position) =
 7379            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7380
 7381        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7382            self.discard_edit_prediction(false, cx);
 7383            return None;
 7384        }
 7385
 7386        self.update_visible_edit_prediction(window, cx);
 7387
 7388        if !user_requested
 7389            && (!self.should_show_edit_predictions()
 7390                || !self.is_focused(window)
 7391                || buffer.read(cx).is_empty())
 7392        {
 7393            self.discard_edit_prediction(false, cx);
 7394            return None;
 7395        }
 7396
 7397        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7398        Some(())
 7399    }
 7400
 7401    fn show_edit_predictions_in_menu(&self) -> bool {
 7402        match self.edit_prediction_settings {
 7403            EditPredictionSettings::Disabled => false,
 7404            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7405        }
 7406    }
 7407
 7408    pub fn edit_predictions_enabled(&self) -> bool {
 7409        match self.edit_prediction_settings {
 7410            EditPredictionSettings::Disabled => false,
 7411            EditPredictionSettings::Enabled { .. } => true,
 7412        }
 7413    }
 7414
 7415    fn edit_prediction_requires_modifier(&self) -> bool {
 7416        match self.edit_prediction_settings {
 7417            EditPredictionSettings::Disabled => false,
 7418            EditPredictionSettings::Enabled {
 7419                preview_requires_modifier,
 7420                ..
 7421            } => preview_requires_modifier,
 7422        }
 7423    }
 7424
 7425    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7426        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7427            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7428            self.discard_edit_prediction(false, cx);
 7429        } else {
 7430            let selection = self.selections.newest_anchor();
 7431            let cursor = selection.head();
 7432
 7433            if let Some((buffer, cursor_buffer_position)) =
 7434                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7435            {
 7436                self.edit_prediction_settings =
 7437                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7438            }
 7439        }
 7440    }
 7441
 7442    fn edit_prediction_settings_at_position(
 7443        &self,
 7444        buffer: &Entity<Buffer>,
 7445        buffer_position: language::Anchor,
 7446        cx: &App,
 7447    ) -> EditPredictionSettings {
 7448        if !self.mode.is_full()
 7449            || !self.show_edit_predictions_override.unwrap_or(true)
 7450            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7451        {
 7452            return EditPredictionSettings::Disabled;
 7453        }
 7454
 7455        let buffer = buffer.read(cx);
 7456
 7457        let file = buffer.file();
 7458
 7459        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7460            return EditPredictionSettings::Disabled;
 7461        };
 7462
 7463        let by_provider = matches!(
 7464            self.menu_edit_predictions_policy,
 7465            MenuEditPredictionsPolicy::ByProvider
 7466        );
 7467
 7468        let show_in_menu = by_provider
 7469            && self
 7470                .edit_prediction_provider
 7471                .as_ref()
 7472                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7473
 7474        let preview_requires_modifier =
 7475            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7476
 7477        EditPredictionSettings::Enabled {
 7478            show_in_menu,
 7479            preview_requires_modifier,
 7480        }
 7481    }
 7482
 7483    fn should_show_edit_predictions(&self) -> bool {
 7484        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7485    }
 7486
 7487    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7488        matches!(
 7489            self.edit_prediction_preview,
 7490            EditPredictionPreview::Active { .. }
 7491        )
 7492    }
 7493
 7494    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7495        let cursor = self.selections.newest_anchor().head();
 7496        if let Some((buffer, cursor_position)) =
 7497            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7498        {
 7499            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7500        } else {
 7501            false
 7502        }
 7503    }
 7504
 7505    pub fn supports_minimap(&self, cx: &App) -> bool {
 7506        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7507    }
 7508
 7509    fn edit_predictions_enabled_in_buffer(
 7510        &self,
 7511        buffer: &Entity<Buffer>,
 7512        buffer_position: language::Anchor,
 7513        cx: &App,
 7514    ) -> bool {
 7515        maybe!({
 7516            if self.read_only(cx) {
 7517                return Some(false);
 7518            }
 7519            let provider = self.edit_prediction_provider()?;
 7520            if !provider.is_enabled(buffer, buffer_position, cx) {
 7521                return Some(false);
 7522            }
 7523            let buffer = buffer.read(cx);
 7524            let Some(file) = buffer.file() else {
 7525                return Some(true);
 7526            };
 7527            let settings = all_language_settings(Some(file), cx);
 7528            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7529        })
 7530        .unwrap_or(false)
 7531    }
 7532
 7533    pub fn show_edit_prediction(
 7534        &mut self,
 7535        _: &ShowEditPrediction,
 7536        window: &mut Window,
 7537        cx: &mut Context<Self>,
 7538    ) {
 7539        if !self.has_active_edit_prediction() {
 7540            self.refresh_edit_prediction(false, true, window, cx);
 7541            return;
 7542        }
 7543
 7544        self.update_visible_edit_prediction(window, cx);
 7545    }
 7546
 7547    pub fn display_cursor_names(
 7548        &mut self,
 7549        _: &DisplayCursorNames,
 7550        window: &mut Window,
 7551        cx: &mut Context<Self>,
 7552    ) {
 7553        self.show_cursor_names(window, cx);
 7554    }
 7555
 7556    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7557        self.show_cursor_names = true;
 7558        cx.notify();
 7559        cx.spawn_in(window, async move |this, cx| {
 7560            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7561            this.update(cx, |this, cx| {
 7562                this.show_cursor_names = false;
 7563                cx.notify()
 7564            })
 7565            .ok()
 7566        })
 7567        .detach();
 7568    }
 7569
 7570    pub fn accept_partial_edit_prediction(
 7571        &mut self,
 7572        granularity: EditPredictionGranularity,
 7573        window: &mut Window,
 7574        cx: &mut Context<Self>,
 7575    ) {
 7576        if self.show_edit_predictions_in_menu() {
 7577            self.hide_context_menu(window, cx);
 7578        }
 7579
 7580        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7581            return;
 7582        };
 7583
 7584        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7585            return;
 7586        }
 7587
 7588        match &active_edit_prediction.completion {
 7589            EditPrediction::MoveWithin { target, .. } => {
 7590                let target = *target;
 7591
 7592                if matches!(granularity, EditPredictionGranularity::Full) {
 7593                    if let Some(position_map) = &self.last_position_map {
 7594                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7595                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7596
 7597                        if is_visible || !self.edit_prediction_requires_modifier() {
 7598                            self.unfold_ranges(&[target..target], true, false, cx);
 7599                            self.change_selections(
 7600                                SelectionEffects::scroll(Autoscroll::newest()),
 7601                                window,
 7602                                cx,
 7603                                |selections| {
 7604                                    selections.select_anchor_ranges([target..target]);
 7605                                },
 7606                            );
 7607                            self.clear_row_highlights::<EditPredictionPreview>();
 7608                            self.edit_prediction_preview
 7609                                .set_previous_scroll_position(None);
 7610                        } else {
 7611                            // Highlight and request scroll
 7612                            self.edit_prediction_preview
 7613                                .set_previous_scroll_position(Some(
 7614                                    position_map.snapshot.scroll_anchor,
 7615                                ));
 7616                            self.highlight_rows::<EditPredictionPreview>(
 7617                                target..target,
 7618                                cx.theme().colors().editor_highlighted_line_background,
 7619                                RowHighlightOptions {
 7620                                    autoscroll: true,
 7621                                    ..Default::default()
 7622                                },
 7623                                cx,
 7624                            );
 7625                            self.request_autoscroll(Autoscroll::fit(), cx);
 7626                        }
 7627                    }
 7628                } else {
 7629                    self.change_selections(
 7630                        SelectionEffects::scroll(Autoscroll::newest()),
 7631                        window,
 7632                        cx,
 7633                        |selections| {
 7634                            selections.select_anchor_ranges([target..target]);
 7635                        },
 7636                    );
 7637                }
 7638            }
 7639            EditPrediction::MoveOutside { snapshot, target } => {
 7640                if let Some(workspace) = self.workspace() {
 7641                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7642                        .detach_and_log_err(cx);
 7643                }
 7644            }
 7645            EditPrediction::Edit { edits, .. } => {
 7646                self.report_edit_prediction_event(
 7647                    active_edit_prediction.completion_id.clone(),
 7648                    true,
 7649                    cx,
 7650                );
 7651
 7652                match granularity {
 7653                    EditPredictionGranularity::Full => {
 7654                        if let Some(provider) = self.edit_prediction_provider() {
 7655                            provider.accept(cx);
 7656                        }
 7657
 7658                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7659                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7660                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7661
 7662                        self.buffer.update(cx, |buffer, cx| {
 7663                            buffer.edit(edits.iter().cloned(), None, cx)
 7664                        });
 7665
 7666                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7667                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7668                        });
 7669
 7670                        let selections = self.selections.disjoint_anchors_arc();
 7671                        if let Some(transaction_id_now) =
 7672                            self.buffer.read(cx).last_transaction_id(cx)
 7673                        {
 7674                            if transaction_id_prev != Some(transaction_id_now) {
 7675                                self.selection_history
 7676                                    .insert_transaction(transaction_id_now, selections);
 7677                            }
 7678                        }
 7679
 7680                        self.update_visible_edit_prediction(window, cx);
 7681                        if self.active_edit_prediction.is_none() {
 7682                            self.refresh_edit_prediction(true, true, window, cx);
 7683                        }
 7684                        cx.notify();
 7685                    }
 7686                    _ => {
 7687                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7688                        let cursor_offset = self
 7689                            .selections
 7690                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7691                            .head();
 7692
 7693                        let insertion = edits.iter().find_map(|(range, text)| {
 7694                            let range = range.to_offset(&snapshot);
 7695                            if range.is_empty() && range.start == cursor_offset {
 7696                                Some(text)
 7697                            } else {
 7698                                None
 7699                            }
 7700                        });
 7701
 7702                        if let Some(text) = insertion {
 7703                            let text_to_insert = match granularity {
 7704                                EditPredictionGranularity::Word => {
 7705                                    let mut partial = text
 7706                                        .chars()
 7707                                        .by_ref()
 7708                                        .take_while(|c| c.is_alphabetic())
 7709                                        .collect::<String>();
 7710                                    if partial.is_empty() {
 7711                                        partial = text
 7712                                            .chars()
 7713                                            .by_ref()
 7714                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7715                                            .collect::<String>();
 7716                                    }
 7717                                    partial
 7718                                }
 7719                                EditPredictionGranularity::Line => {
 7720                                    if let Some(line) = text.split_inclusive('\n').next() {
 7721                                        line.to_string()
 7722                                    } else {
 7723                                        text.to_string()
 7724                                    }
 7725                                }
 7726                                EditPredictionGranularity::Full => unreachable!(),
 7727                            };
 7728
 7729                            cx.emit(EditorEvent::InputHandled {
 7730                                utf16_range_to_replace: None,
 7731                                text: text_to_insert.clone().into(),
 7732                            });
 7733
 7734                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7735                            self.refresh_edit_prediction(true, true, window, cx);
 7736                            cx.notify();
 7737                        } else {
 7738                            self.accept_partial_edit_prediction(
 7739                                EditPredictionGranularity::Full,
 7740                                window,
 7741                                cx,
 7742                            );
 7743                        }
 7744                    }
 7745                }
 7746            }
 7747        }
 7748
 7749        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7750    }
 7751
 7752    pub fn accept_next_word_edit_prediction(
 7753        &mut self,
 7754        _: &AcceptNextWordEditPrediction,
 7755        window: &mut Window,
 7756        cx: &mut Context<Self>,
 7757    ) {
 7758        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7759    }
 7760
 7761    pub fn accept_next_line_edit_prediction(
 7762        &mut self,
 7763        _: &AcceptNextLineEditPrediction,
 7764        window: &mut Window,
 7765        cx: &mut Context<Self>,
 7766    ) {
 7767        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7768    }
 7769
 7770    pub fn accept_edit_prediction(
 7771        &mut self,
 7772        _: &AcceptEditPrediction,
 7773        window: &mut Window,
 7774        cx: &mut Context<Self>,
 7775    ) {
 7776        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7777    }
 7778
 7779    fn discard_edit_prediction(
 7780        &mut self,
 7781        should_report_edit_prediction_event: bool,
 7782        cx: &mut Context<Self>,
 7783    ) -> bool {
 7784        if should_report_edit_prediction_event {
 7785            let completion_id = self
 7786                .active_edit_prediction
 7787                .as_ref()
 7788                .and_then(|active_completion| active_completion.completion_id.clone());
 7789
 7790            self.report_edit_prediction_event(completion_id, false, cx);
 7791        }
 7792
 7793        if let Some(provider) = self.edit_prediction_provider() {
 7794            provider.discard(cx);
 7795        }
 7796
 7797        self.take_active_edit_prediction(cx)
 7798    }
 7799
 7800    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7801        let Some(provider) = self.edit_prediction_provider() else {
 7802            return;
 7803        };
 7804
 7805        let Some((_, buffer, _)) = self
 7806            .buffer
 7807            .read(cx)
 7808            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7809        else {
 7810            return;
 7811        };
 7812
 7813        let extension = buffer
 7814            .read(cx)
 7815            .file()
 7816            .and_then(|file| Some(file.path().extension()?.to_string()));
 7817
 7818        let event_type = match accepted {
 7819            true => "Edit Prediction Accepted",
 7820            false => "Edit Prediction Discarded",
 7821        };
 7822        telemetry::event!(
 7823            event_type,
 7824            provider = provider.name(),
 7825            prediction_id = id,
 7826            suggestion_accepted = accepted,
 7827            file_extension = extension,
 7828        );
 7829    }
 7830
 7831    fn open_editor_at_anchor(
 7832        snapshot: &language::BufferSnapshot,
 7833        target: language::Anchor,
 7834        workspace: &Entity<Workspace>,
 7835        window: &mut Window,
 7836        cx: &mut App,
 7837    ) -> Task<Result<()>> {
 7838        workspace.update(cx, |workspace, cx| {
 7839            let path = snapshot.file().map(|file| file.full_path(cx));
 7840            let Some(path) =
 7841                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7842            else {
 7843                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7844            };
 7845            let target = text::ToPoint::to_point(&target, snapshot);
 7846            let item = workspace.open_path(path, None, true, window, cx);
 7847            window.spawn(cx, async move |cx| {
 7848                let Some(editor) = item.await?.downcast::<Editor>() else {
 7849                    return Ok(());
 7850                };
 7851                editor
 7852                    .update_in(cx, |editor, window, cx| {
 7853                        editor.go_to_singleton_buffer_point(target, window, cx);
 7854                    })
 7855                    .ok();
 7856                anyhow::Ok(())
 7857            })
 7858        })
 7859    }
 7860
 7861    pub fn has_active_edit_prediction(&self) -> bool {
 7862        self.active_edit_prediction.is_some()
 7863    }
 7864
 7865    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7866        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7867            return false;
 7868        };
 7869
 7870        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7871        self.clear_highlights::<EditPredictionHighlight>(cx);
 7872        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7873        true
 7874    }
 7875
 7876    /// Returns true when we're displaying the edit prediction popover below the cursor
 7877    /// like we are not previewing and the LSP autocomplete menu is visible
 7878    /// or we are in `when_holding_modifier` mode.
 7879    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7880        if self.edit_prediction_preview_is_active()
 7881            || !self.show_edit_predictions_in_menu()
 7882            || !self.edit_predictions_enabled()
 7883        {
 7884            return false;
 7885        }
 7886
 7887        if self.has_visible_completions_menu() {
 7888            return true;
 7889        }
 7890
 7891        has_completion && self.edit_prediction_requires_modifier()
 7892    }
 7893
 7894    fn handle_modifiers_changed(
 7895        &mut self,
 7896        modifiers: Modifiers,
 7897        position_map: &PositionMap,
 7898        window: &mut Window,
 7899        cx: &mut Context<Self>,
 7900    ) {
 7901        // Ensure that the edit prediction preview is updated, even when not
 7902        // enabled, if there's an active edit prediction preview.
 7903        if self.show_edit_predictions_in_menu()
 7904            || matches!(
 7905                self.edit_prediction_preview,
 7906                EditPredictionPreview::Active { .. }
 7907            )
 7908        {
 7909            self.update_edit_prediction_preview(&modifiers, window, cx);
 7910        }
 7911
 7912        self.update_selection_mode(&modifiers, position_map, window, cx);
 7913
 7914        let mouse_position = window.mouse_position();
 7915        if !position_map.text_hitbox.is_hovered(window) {
 7916            return;
 7917        }
 7918
 7919        self.update_hovered_link(
 7920            position_map.point_for_position(mouse_position),
 7921            &position_map.snapshot,
 7922            modifiers,
 7923            window,
 7924            cx,
 7925        )
 7926    }
 7927
 7928    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7929        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7930            MultiCursorModifier::Alt => modifiers.secondary(),
 7931            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7932        }
 7933    }
 7934
 7935    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7936        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7937            MultiCursorModifier::Alt => modifiers.alt,
 7938            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7939        }
 7940    }
 7941
 7942    fn columnar_selection_mode(
 7943        modifiers: &Modifiers,
 7944        cx: &mut Context<Self>,
 7945    ) -> Option<ColumnarMode> {
 7946        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7947            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7948                Some(ColumnarMode::FromMouse)
 7949            } else if Self::is_alt_pressed(modifiers, cx) {
 7950                Some(ColumnarMode::FromSelection)
 7951            } else {
 7952                None
 7953            }
 7954        } else {
 7955            None
 7956        }
 7957    }
 7958
 7959    fn update_selection_mode(
 7960        &mut self,
 7961        modifiers: &Modifiers,
 7962        position_map: &PositionMap,
 7963        window: &mut Window,
 7964        cx: &mut Context<Self>,
 7965    ) {
 7966        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7967            return;
 7968        };
 7969        if self.selections.pending_anchor().is_none() {
 7970            return;
 7971        }
 7972
 7973        let mouse_position = window.mouse_position();
 7974        let point_for_position = position_map.point_for_position(mouse_position);
 7975        let position = point_for_position.previous_valid;
 7976
 7977        self.select(
 7978            SelectPhase::BeginColumnar {
 7979                position,
 7980                reset: false,
 7981                mode,
 7982                goal_column: point_for_position.exact_unclipped.column(),
 7983            },
 7984            window,
 7985            cx,
 7986        );
 7987    }
 7988
 7989    fn update_edit_prediction_preview(
 7990        &mut self,
 7991        modifiers: &Modifiers,
 7992        window: &mut Window,
 7993        cx: &mut Context<Self>,
 7994    ) {
 7995        let mut modifiers_held = false;
 7996
 7997        // Check bindings for all granularities.
 7998        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 7999        let granularities = [
 8000            EditPredictionGranularity::Full,
 8001            EditPredictionGranularity::Line,
 8002            EditPredictionGranularity::Word,
 8003        ];
 8004
 8005        for granularity in granularities {
 8006            if let Some(keystroke) = self
 8007                .accept_edit_prediction_keybind(granularity, window, cx)
 8008                .keystroke()
 8009            {
 8010                modifiers_held = modifiers_held
 8011                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8012            }
 8013        }
 8014
 8015        if modifiers_held {
 8016            if matches!(
 8017                self.edit_prediction_preview,
 8018                EditPredictionPreview::Inactive { .. }
 8019            ) {
 8020                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 8021                    provider.provider.did_show(cx)
 8022                }
 8023
 8024                self.edit_prediction_preview = EditPredictionPreview::Active {
 8025                    previous_scroll_position: None,
 8026                    since: Instant::now(),
 8027                };
 8028
 8029                self.update_visible_edit_prediction(window, cx);
 8030                cx.notify();
 8031            }
 8032        } else if let EditPredictionPreview::Active {
 8033            previous_scroll_position,
 8034            since,
 8035        } = self.edit_prediction_preview
 8036        {
 8037            if let (Some(previous_scroll_position), Some(position_map)) =
 8038                (previous_scroll_position, self.last_position_map.as_ref())
 8039            {
 8040                self.set_scroll_position(
 8041                    previous_scroll_position
 8042                        .scroll_position(&position_map.snapshot.display_snapshot),
 8043                    window,
 8044                    cx,
 8045                );
 8046            }
 8047
 8048            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8049                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8050            };
 8051            self.clear_row_highlights::<EditPredictionPreview>();
 8052            self.update_visible_edit_prediction(window, cx);
 8053            cx.notify();
 8054        }
 8055    }
 8056
 8057    fn update_visible_edit_prediction(
 8058        &mut self,
 8059        _window: &mut Window,
 8060        cx: &mut Context<Self>,
 8061    ) -> Option<()> {
 8062        if DisableAiSettings::get_global(cx).disable_ai {
 8063            return None;
 8064        }
 8065
 8066        if self.ime_transaction.is_some() {
 8067            self.discard_edit_prediction(false, cx);
 8068            return None;
 8069        }
 8070
 8071        let selection = self.selections.newest_anchor();
 8072        let cursor = selection.head();
 8073        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8074        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8075        let excerpt_id = cursor.excerpt_id;
 8076
 8077        let show_in_menu = self.show_edit_predictions_in_menu();
 8078        let completions_menu_has_precedence = !show_in_menu
 8079            && (self.context_menu.borrow().is_some()
 8080                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8081
 8082        if completions_menu_has_precedence
 8083            || !offset_selection.is_empty()
 8084            || self
 8085                .active_edit_prediction
 8086                .as_ref()
 8087                .is_some_and(|completion| {
 8088                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8089                        return false;
 8090                    };
 8091                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8092                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8093                    !invalidation_range.contains(&offset_selection.head())
 8094                })
 8095        {
 8096            self.discard_edit_prediction(false, cx);
 8097            return None;
 8098        }
 8099
 8100        self.take_active_edit_prediction(cx);
 8101        let Some(provider) = self.edit_prediction_provider() else {
 8102            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8103            return None;
 8104        };
 8105
 8106        let (buffer, cursor_buffer_position) =
 8107            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8108
 8109        self.edit_prediction_settings =
 8110            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8111
 8112        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8113
 8114        if self.edit_prediction_indent_conflict {
 8115            let cursor_point = cursor.to_point(&multibuffer);
 8116            let mut suggested_indent = None;
 8117            multibuffer.suggested_indents_callback(
 8118                cursor_point.row..cursor_point.row + 1,
 8119                |_, indent| {
 8120                    suggested_indent = Some(indent);
 8121                    ControlFlow::Break(())
 8122                },
 8123                cx,
 8124            );
 8125
 8126            if let Some(indent) = suggested_indent
 8127                && indent.len == cursor_point.column
 8128            {
 8129                self.edit_prediction_indent_conflict = false;
 8130            }
 8131        }
 8132
 8133        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8134
 8135        let (completion_id, edits, edit_preview) = match edit_prediction {
 8136            edit_prediction_types::EditPrediction::Local {
 8137                id,
 8138                edits,
 8139                edit_preview,
 8140            } => (id, edits, edit_preview),
 8141            edit_prediction_types::EditPrediction::Jump {
 8142                id,
 8143                snapshot,
 8144                target,
 8145            } => {
 8146                self.stale_edit_prediction_in_menu = None;
 8147                self.active_edit_prediction = Some(EditPredictionState {
 8148                    inlay_ids: vec![],
 8149                    completion: EditPrediction::MoveOutside { snapshot, target },
 8150                    completion_id: id,
 8151                    invalidation_range: None,
 8152                });
 8153                cx.notify();
 8154                return Some(());
 8155            }
 8156        };
 8157
 8158        let edits = edits
 8159            .into_iter()
 8160            .flat_map(|(range, new_text)| {
 8161                Some((
 8162                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8163                    new_text,
 8164                ))
 8165            })
 8166            .collect::<Vec<_>>();
 8167        if edits.is_empty() {
 8168            return None;
 8169        }
 8170
 8171        let first_edit_start = edits.first().unwrap().0.start;
 8172        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8173        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8174
 8175        let last_edit_end = edits.last().unwrap().0.end;
 8176        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8177        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8178
 8179        let cursor_row = cursor.to_point(&multibuffer).row;
 8180
 8181        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8182
 8183        let mut inlay_ids = Vec::new();
 8184        let invalidation_row_range;
 8185        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8186            Some(cursor_row..edit_end_row)
 8187        } else if cursor_row > edit_end_row {
 8188            Some(edit_start_row..cursor_row)
 8189        } else {
 8190            None
 8191        };
 8192        let supports_jump = self
 8193            .edit_prediction_provider
 8194            .as_ref()
 8195            .map(|provider| provider.provider.supports_jump_to_edit())
 8196            .unwrap_or(true);
 8197
 8198        let is_move = supports_jump
 8199            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8200        let completion = if is_move {
 8201            invalidation_row_range =
 8202                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8203            let target = first_edit_start;
 8204            EditPrediction::MoveWithin { target, snapshot }
 8205        } else {
 8206            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8207                && !self.edit_predictions_hidden_for_vim_mode;
 8208
 8209            if show_completions_in_buffer {
 8210                if let Some(provider) = &self.edit_prediction_provider {
 8211                    provider.provider.did_show(cx);
 8212                }
 8213                if edits
 8214                    .iter()
 8215                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8216                {
 8217                    let mut inlays = Vec::new();
 8218                    for (range, new_text) in &edits {
 8219                        let inlay = Inlay::edit_prediction(
 8220                            post_inc(&mut self.next_inlay_id),
 8221                            range.start,
 8222                            new_text.as_ref(),
 8223                        );
 8224                        inlay_ids.push(inlay.id);
 8225                        inlays.push(inlay);
 8226                    }
 8227
 8228                    self.splice_inlays(&[], inlays, cx);
 8229                } else {
 8230                    let background_color = cx.theme().status().deleted_background;
 8231                    self.highlight_text::<EditPredictionHighlight>(
 8232                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8233                        HighlightStyle {
 8234                            background_color: Some(background_color),
 8235                            ..Default::default()
 8236                        },
 8237                        cx,
 8238                    );
 8239                }
 8240            }
 8241
 8242            invalidation_row_range = edit_start_row..edit_end_row;
 8243
 8244            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8245                if provider.show_tab_accept_marker() {
 8246                    EditDisplayMode::TabAccept
 8247                } else {
 8248                    EditDisplayMode::Inline
 8249                }
 8250            } else {
 8251                EditDisplayMode::DiffPopover
 8252            };
 8253
 8254            EditPrediction::Edit {
 8255                edits,
 8256                edit_preview,
 8257                display_mode,
 8258                snapshot,
 8259            }
 8260        };
 8261
 8262        let invalidation_range = multibuffer
 8263            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8264            ..multibuffer.anchor_after(Point::new(
 8265                invalidation_row_range.end,
 8266                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8267            ));
 8268
 8269        self.stale_edit_prediction_in_menu = None;
 8270        self.active_edit_prediction = Some(EditPredictionState {
 8271            inlay_ids,
 8272            completion,
 8273            completion_id,
 8274            invalidation_range: Some(invalidation_range),
 8275        });
 8276
 8277        cx.notify();
 8278
 8279        Some(())
 8280    }
 8281
 8282    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8283        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8284    }
 8285
 8286    fn clear_tasks(&mut self) {
 8287        self.tasks.clear()
 8288    }
 8289
 8290    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8291        if self.tasks.insert(key, value).is_some() {
 8292            // This case should hopefully be rare, but just in case...
 8293            log::error!(
 8294                "multiple different run targets found on a single line, only the last target will be rendered"
 8295            )
 8296        }
 8297    }
 8298
 8299    /// Get all display points of breakpoints that will be rendered within editor
 8300    ///
 8301    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8302    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8303    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8304    fn active_breakpoints(
 8305        &self,
 8306        range: Range<DisplayRow>,
 8307        window: &mut Window,
 8308        cx: &mut Context<Self>,
 8309    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8310        let mut breakpoint_display_points = HashMap::default();
 8311
 8312        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8313            return breakpoint_display_points;
 8314        };
 8315
 8316        let snapshot = self.snapshot(window, cx);
 8317
 8318        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8319        let Some(project) = self.project() else {
 8320            return breakpoint_display_points;
 8321        };
 8322
 8323        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8324            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8325
 8326        for (buffer_snapshot, range, excerpt_id) in
 8327            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8328        {
 8329            let Some(buffer) = project
 8330                .read(cx)
 8331                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8332            else {
 8333                continue;
 8334            };
 8335            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8336                &buffer,
 8337                Some(
 8338                    buffer_snapshot.anchor_before(range.start)
 8339                        ..buffer_snapshot.anchor_after(range.end),
 8340                ),
 8341                buffer_snapshot,
 8342                cx,
 8343            );
 8344            for (breakpoint, state) in breakpoints {
 8345                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8346                let position = multi_buffer_anchor
 8347                    .to_point(&multi_buffer_snapshot)
 8348                    .to_display_point(&snapshot);
 8349
 8350                breakpoint_display_points.insert(
 8351                    position.row(),
 8352                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8353                );
 8354            }
 8355        }
 8356
 8357        breakpoint_display_points
 8358    }
 8359
 8360    fn breakpoint_context_menu(
 8361        &self,
 8362        anchor: Anchor,
 8363        window: &mut Window,
 8364        cx: &mut Context<Self>,
 8365    ) -> Entity<ui::ContextMenu> {
 8366        let weak_editor = cx.weak_entity();
 8367        let focus_handle = self.focus_handle(cx);
 8368
 8369        let row = self
 8370            .buffer
 8371            .read(cx)
 8372            .snapshot(cx)
 8373            .summary_for_anchor::<Point>(&anchor)
 8374            .row;
 8375
 8376        let breakpoint = self
 8377            .breakpoint_at_row(row, window, cx)
 8378            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8379
 8380        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8381            "Edit Log Breakpoint"
 8382        } else {
 8383            "Set Log Breakpoint"
 8384        };
 8385
 8386        let condition_breakpoint_msg = if breakpoint
 8387            .as_ref()
 8388            .is_some_and(|bp| bp.1.condition.is_some())
 8389        {
 8390            "Edit Condition Breakpoint"
 8391        } else {
 8392            "Set Condition Breakpoint"
 8393        };
 8394
 8395        let hit_condition_breakpoint_msg = if breakpoint
 8396            .as_ref()
 8397            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8398        {
 8399            "Edit Hit Condition Breakpoint"
 8400        } else {
 8401            "Set Hit Condition Breakpoint"
 8402        };
 8403
 8404        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8405            "Unset Breakpoint"
 8406        } else {
 8407            "Set Breakpoint"
 8408        };
 8409
 8410        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8411
 8412        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8413            BreakpointState::Enabled => Some("Disable"),
 8414            BreakpointState::Disabled => Some("Enable"),
 8415        });
 8416
 8417        let (anchor, breakpoint) =
 8418            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8419
 8420        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8421            menu.on_blur_subscription(Subscription::new(|| {}))
 8422                .context(focus_handle)
 8423                .when(run_to_cursor, |this| {
 8424                    let weak_editor = weak_editor.clone();
 8425                    this.entry("Run to cursor", None, move |window, cx| {
 8426                        weak_editor
 8427                            .update(cx, |editor, cx| {
 8428                                editor.change_selections(
 8429                                    SelectionEffects::no_scroll(),
 8430                                    window,
 8431                                    cx,
 8432                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8433                                );
 8434                            })
 8435                            .ok();
 8436
 8437                        window.dispatch_action(Box::new(RunToCursor), cx);
 8438                    })
 8439                    .separator()
 8440                })
 8441                .when_some(toggle_state_msg, |this, msg| {
 8442                    this.entry(msg, None, {
 8443                        let weak_editor = weak_editor.clone();
 8444                        let breakpoint = breakpoint.clone();
 8445                        move |_window, cx| {
 8446                            weak_editor
 8447                                .update(cx, |this, cx| {
 8448                                    this.edit_breakpoint_at_anchor(
 8449                                        anchor,
 8450                                        breakpoint.as_ref().clone(),
 8451                                        BreakpointEditAction::InvertState,
 8452                                        cx,
 8453                                    );
 8454                                })
 8455                                .log_err();
 8456                        }
 8457                    })
 8458                })
 8459                .entry(set_breakpoint_msg, None, {
 8460                    let weak_editor = weak_editor.clone();
 8461                    let breakpoint = breakpoint.clone();
 8462                    move |_window, cx| {
 8463                        weak_editor
 8464                            .update(cx, |this, cx| {
 8465                                this.edit_breakpoint_at_anchor(
 8466                                    anchor,
 8467                                    breakpoint.as_ref().clone(),
 8468                                    BreakpointEditAction::Toggle,
 8469                                    cx,
 8470                                );
 8471                            })
 8472                            .log_err();
 8473                    }
 8474                })
 8475                .entry(log_breakpoint_msg, None, {
 8476                    let breakpoint = breakpoint.clone();
 8477                    let weak_editor = weak_editor.clone();
 8478                    move |window, cx| {
 8479                        weak_editor
 8480                            .update(cx, |this, cx| {
 8481                                this.add_edit_breakpoint_block(
 8482                                    anchor,
 8483                                    breakpoint.as_ref(),
 8484                                    BreakpointPromptEditAction::Log,
 8485                                    window,
 8486                                    cx,
 8487                                );
 8488                            })
 8489                            .log_err();
 8490                    }
 8491                })
 8492                .entry(condition_breakpoint_msg, None, {
 8493                    let breakpoint = breakpoint.clone();
 8494                    let weak_editor = weak_editor.clone();
 8495                    move |window, cx| {
 8496                        weak_editor
 8497                            .update(cx, |this, cx| {
 8498                                this.add_edit_breakpoint_block(
 8499                                    anchor,
 8500                                    breakpoint.as_ref(),
 8501                                    BreakpointPromptEditAction::Condition,
 8502                                    window,
 8503                                    cx,
 8504                                );
 8505                            })
 8506                            .log_err();
 8507                    }
 8508                })
 8509                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8510                    weak_editor
 8511                        .update(cx, |this, cx| {
 8512                            this.add_edit_breakpoint_block(
 8513                                anchor,
 8514                                breakpoint.as_ref(),
 8515                                BreakpointPromptEditAction::HitCondition,
 8516                                window,
 8517                                cx,
 8518                            );
 8519                        })
 8520                        .log_err();
 8521                })
 8522        })
 8523    }
 8524
 8525    fn render_breakpoint(
 8526        &self,
 8527        position: Anchor,
 8528        row: DisplayRow,
 8529        breakpoint: &Breakpoint,
 8530        state: Option<BreakpointSessionState>,
 8531        cx: &mut Context<Self>,
 8532    ) -> IconButton {
 8533        let is_rejected = state.is_some_and(|s| !s.verified);
 8534        // Is it a breakpoint that shows up when hovering over gutter?
 8535        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8536            (false, false),
 8537            |PhantomBreakpointIndicator {
 8538                 is_active,
 8539                 display_row,
 8540                 collides_with_existing_breakpoint,
 8541             }| {
 8542                (
 8543                    is_active && display_row == row,
 8544                    collides_with_existing_breakpoint,
 8545                )
 8546            },
 8547        );
 8548
 8549        let (color, icon) = {
 8550            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8551                (false, false) => ui::IconName::DebugBreakpoint,
 8552                (true, false) => ui::IconName::DebugLogBreakpoint,
 8553                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8554                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8555            };
 8556
 8557            let color = cx.theme().colors();
 8558
 8559            let color = if is_phantom {
 8560                if collides_with_existing {
 8561                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8562                } else {
 8563                    Color::Hint
 8564                }
 8565            } else if is_rejected {
 8566                Color::Disabled
 8567            } else {
 8568                Color::Debugger
 8569            };
 8570
 8571            (color, icon)
 8572        };
 8573
 8574        let breakpoint = Arc::from(breakpoint.clone());
 8575
 8576        let alt_as_text = gpui::Keystroke {
 8577            modifiers: Modifiers::secondary_key(),
 8578            ..Default::default()
 8579        };
 8580        let primary_action_text = if breakpoint.is_disabled() {
 8581            "Enable breakpoint"
 8582        } else if is_phantom && !collides_with_existing {
 8583            "Set breakpoint"
 8584        } else {
 8585            "Unset breakpoint"
 8586        };
 8587        let focus_handle = self.focus_handle.clone();
 8588
 8589        let meta = if is_rejected {
 8590            SharedString::from("No executable code is associated with this line.")
 8591        } else if collides_with_existing && !breakpoint.is_disabled() {
 8592            SharedString::from(format!(
 8593                "{alt_as_text}-click to disable,\nright-click for more options."
 8594            ))
 8595        } else {
 8596            SharedString::from("Right-click for more options.")
 8597        };
 8598        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8599            .icon_size(IconSize::XSmall)
 8600            .size(ui::ButtonSize::None)
 8601            .when(is_rejected, |this| {
 8602                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8603            })
 8604            .icon_color(color)
 8605            .style(ButtonStyle::Transparent)
 8606            .on_click(cx.listener({
 8607                move |editor, event: &ClickEvent, window, cx| {
 8608                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8609                        BreakpointEditAction::InvertState
 8610                    } else {
 8611                        BreakpointEditAction::Toggle
 8612                    };
 8613
 8614                    window.focus(&editor.focus_handle(cx), cx);
 8615                    editor.edit_breakpoint_at_anchor(
 8616                        position,
 8617                        breakpoint.as_ref().clone(),
 8618                        edit_action,
 8619                        cx,
 8620                    );
 8621                }
 8622            }))
 8623            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8624                editor.set_breakpoint_context_menu(
 8625                    row,
 8626                    Some(position),
 8627                    event.position(),
 8628                    window,
 8629                    cx,
 8630                );
 8631            }))
 8632            .tooltip(move |_window, cx| {
 8633                Tooltip::with_meta_in(
 8634                    primary_action_text,
 8635                    Some(&ToggleBreakpoint),
 8636                    meta.clone(),
 8637                    &focus_handle,
 8638                    cx,
 8639                )
 8640            })
 8641    }
 8642
 8643    fn build_tasks_context(
 8644        project: &Entity<Project>,
 8645        buffer: &Entity<Buffer>,
 8646        buffer_row: u32,
 8647        tasks: &Arc<RunnableTasks>,
 8648        cx: &mut Context<Self>,
 8649    ) -> Task<Option<task::TaskContext>> {
 8650        let position = Point::new(buffer_row, tasks.column);
 8651        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8652        let location = Location {
 8653            buffer: buffer.clone(),
 8654            range: range_start..range_start,
 8655        };
 8656        // Fill in the environmental variables from the tree-sitter captures
 8657        let mut captured_task_variables = TaskVariables::default();
 8658        for (capture_name, value) in tasks.extra_variables.clone() {
 8659            captured_task_variables.insert(
 8660                task::VariableName::Custom(capture_name.into()),
 8661                value.clone(),
 8662            );
 8663        }
 8664        project.update(cx, |project, cx| {
 8665            project.task_store().update(cx, |task_store, cx| {
 8666                task_store.task_context_for_location(captured_task_variables, location, cx)
 8667            })
 8668        })
 8669    }
 8670
 8671    pub fn spawn_nearest_task(
 8672        &mut self,
 8673        action: &SpawnNearestTask,
 8674        window: &mut Window,
 8675        cx: &mut Context<Self>,
 8676    ) {
 8677        let Some((workspace, _)) = self.workspace.clone() else {
 8678            return;
 8679        };
 8680        let Some(project) = self.project.clone() else {
 8681            return;
 8682        };
 8683
 8684        // Try to find a closest, enclosing node using tree-sitter that has a task
 8685        let Some((buffer, buffer_row, tasks)) = self
 8686            .find_enclosing_node_task(cx)
 8687            // Or find the task that's closest in row-distance.
 8688            .or_else(|| self.find_closest_task(cx))
 8689        else {
 8690            return;
 8691        };
 8692
 8693        let reveal_strategy = action.reveal;
 8694        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8695        cx.spawn_in(window, async move |_, cx| {
 8696            let context = task_context.await?;
 8697            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8698
 8699            let resolved = &mut resolved_task.resolved;
 8700            resolved.reveal = reveal_strategy;
 8701
 8702            workspace
 8703                .update_in(cx, |workspace, window, cx| {
 8704                    workspace.schedule_resolved_task(
 8705                        task_source_kind,
 8706                        resolved_task,
 8707                        false,
 8708                        window,
 8709                        cx,
 8710                    );
 8711                })
 8712                .ok()
 8713        })
 8714        .detach();
 8715    }
 8716
 8717    fn find_closest_task(
 8718        &mut self,
 8719        cx: &mut Context<Self>,
 8720    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8721        let cursor_row = self
 8722            .selections
 8723            .newest_adjusted(&self.display_snapshot(cx))
 8724            .head()
 8725            .row;
 8726
 8727        let ((buffer_id, row), tasks) = self
 8728            .tasks
 8729            .iter()
 8730            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8731
 8732        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8733        let tasks = Arc::new(tasks.to_owned());
 8734        Some((buffer, *row, tasks))
 8735    }
 8736
 8737    fn find_enclosing_node_task(
 8738        &mut self,
 8739        cx: &mut Context<Self>,
 8740    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8741        let snapshot = self.buffer.read(cx).snapshot(cx);
 8742        let offset = self
 8743            .selections
 8744            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8745            .head();
 8746        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8747        let offset = excerpt.map_offset_to_buffer(offset);
 8748        let buffer_id = excerpt.buffer().remote_id();
 8749
 8750        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8751        let mut cursor = layer.node().walk();
 8752
 8753        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8754            if cursor.node().end_byte() == offset.0 {
 8755                cursor.goto_next_sibling();
 8756            }
 8757        }
 8758
 8759        // Ascend to the smallest ancestor that contains the range and has a task.
 8760        loop {
 8761            let node = cursor.node();
 8762            let node_range = node.byte_range();
 8763            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8764
 8765            // Check if this node contains our offset
 8766            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8767                // If it contains offset, check for task
 8768                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8769                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8770                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8771                }
 8772            }
 8773
 8774            if !cursor.goto_parent() {
 8775                break;
 8776            }
 8777        }
 8778        None
 8779    }
 8780
 8781    fn render_run_indicator(
 8782        &self,
 8783        _style: &EditorStyle,
 8784        is_active: bool,
 8785        row: DisplayRow,
 8786        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8787        cx: &mut Context<Self>,
 8788    ) -> IconButton {
 8789        let color = Color::Muted;
 8790        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8791
 8792        IconButton::new(
 8793            ("run_indicator", row.0 as usize),
 8794            ui::IconName::PlayOutlined,
 8795        )
 8796        .shape(ui::IconButtonShape::Square)
 8797        .icon_size(IconSize::XSmall)
 8798        .icon_color(color)
 8799        .toggle_state(is_active)
 8800        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8801            let quick_launch = match e {
 8802                ClickEvent::Keyboard(_) => true,
 8803                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8804            };
 8805
 8806            window.focus(&editor.focus_handle(cx), cx);
 8807            editor.toggle_code_actions(
 8808                &ToggleCodeActions {
 8809                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8810                    quick_launch,
 8811                },
 8812                window,
 8813                cx,
 8814            );
 8815        }))
 8816        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8817            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8818        }))
 8819    }
 8820
 8821    pub fn context_menu_visible(&self) -> bool {
 8822        !self.edit_prediction_preview_is_active()
 8823            && self
 8824                .context_menu
 8825                .borrow()
 8826                .as_ref()
 8827                .is_some_and(|menu| menu.visible())
 8828    }
 8829
 8830    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8831        self.context_menu
 8832            .borrow()
 8833            .as_ref()
 8834            .map(|menu| menu.origin())
 8835    }
 8836
 8837    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8838        self.context_menu_options = Some(options);
 8839    }
 8840
 8841    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8842    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8843
 8844    fn render_edit_prediction_popover(
 8845        &mut self,
 8846        text_bounds: &Bounds<Pixels>,
 8847        content_origin: gpui::Point<Pixels>,
 8848        right_margin: Pixels,
 8849        editor_snapshot: &EditorSnapshot,
 8850        visible_row_range: Range<DisplayRow>,
 8851        scroll_top: ScrollOffset,
 8852        scroll_bottom: ScrollOffset,
 8853        line_layouts: &[LineWithInvisibles],
 8854        line_height: Pixels,
 8855        scroll_position: gpui::Point<ScrollOffset>,
 8856        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8857        newest_selection_head: Option<DisplayPoint>,
 8858        editor_width: Pixels,
 8859        style: &EditorStyle,
 8860        window: &mut Window,
 8861        cx: &mut App,
 8862    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8863        if self.mode().is_minimap() {
 8864            return None;
 8865        }
 8866        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8867
 8868        if self.edit_prediction_visible_in_cursor_popover(true) {
 8869            return None;
 8870        }
 8871
 8872        match &active_edit_prediction.completion {
 8873            EditPrediction::MoveWithin { target, .. } => {
 8874                let target_display_point = target.to_display_point(editor_snapshot);
 8875
 8876                if self.edit_prediction_requires_modifier() {
 8877                    if !self.edit_prediction_preview_is_active() {
 8878                        return None;
 8879                    }
 8880
 8881                    self.render_edit_prediction_modifier_jump_popover(
 8882                        text_bounds,
 8883                        content_origin,
 8884                        visible_row_range,
 8885                        line_layouts,
 8886                        line_height,
 8887                        scroll_pixel_position,
 8888                        newest_selection_head,
 8889                        target_display_point,
 8890                        window,
 8891                        cx,
 8892                    )
 8893                } else {
 8894                    self.render_edit_prediction_eager_jump_popover(
 8895                        text_bounds,
 8896                        content_origin,
 8897                        editor_snapshot,
 8898                        visible_row_range,
 8899                        scroll_top,
 8900                        scroll_bottom,
 8901                        line_height,
 8902                        scroll_pixel_position,
 8903                        target_display_point,
 8904                        editor_width,
 8905                        window,
 8906                        cx,
 8907                    )
 8908                }
 8909            }
 8910            EditPrediction::Edit {
 8911                display_mode: EditDisplayMode::Inline,
 8912                ..
 8913            } => None,
 8914            EditPrediction::Edit {
 8915                display_mode: EditDisplayMode::TabAccept,
 8916                edits,
 8917                ..
 8918            } => {
 8919                let range = &edits.first()?.0;
 8920                let target_display_point = range.end.to_display_point(editor_snapshot);
 8921
 8922                self.render_edit_prediction_end_of_line_popover(
 8923                    "Accept",
 8924                    editor_snapshot,
 8925                    visible_row_range,
 8926                    target_display_point,
 8927                    line_height,
 8928                    scroll_pixel_position,
 8929                    content_origin,
 8930                    editor_width,
 8931                    window,
 8932                    cx,
 8933                )
 8934            }
 8935            EditPrediction::Edit {
 8936                edits,
 8937                edit_preview,
 8938                display_mode: EditDisplayMode::DiffPopover,
 8939                snapshot,
 8940            } => self.render_edit_prediction_diff_popover(
 8941                text_bounds,
 8942                content_origin,
 8943                right_margin,
 8944                editor_snapshot,
 8945                visible_row_range,
 8946                line_layouts,
 8947                line_height,
 8948                scroll_position,
 8949                scroll_pixel_position,
 8950                newest_selection_head,
 8951                editor_width,
 8952                style,
 8953                edits,
 8954                edit_preview,
 8955                snapshot,
 8956                window,
 8957                cx,
 8958            ),
 8959            EditPrediction::MoveOutside { snapshot, .. } => {
 8960                let mut element = self
 8961                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8962                    .into_any();
 8963
 8964                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8965                let origin_x = text_bounds.size.width - size.width - px(30.);
 8966                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8967                element.prepaint_at(origin, window, cx);
 8968
 8969                Some((element, origin))
 8970            }
 8971        }
 8972    }
 8973
 8974    fn render_edit_prediction_modifier_jump_popover(
 8975        &mut self,
 8976        text_bounds: &Bounds<Pixels>,
 8977        content_origin: gpui::Point<Pixels>,
 8978        visible_row_range: Range<DisplayRow>,
 8979        line_layouts: &[LineWithInvisibles],
 8980        line_height: Pixels,
 8981        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8982        newest_selection_head: Option<DisplayPoint>,
 8983        target_display_point: DisplayPoint,
 8984        window: &mut Window,
 8985        cx: &mut App,
 8986    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8987        let scrolled_content_origin =
 8988            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8989
 8990        const SCROLL_PADDING_Y: Pixels = px(12.);
 8991
 8992        if target_display_point.row() < visible_row_range.start {
 8993            return self.render_edit_prediction_scroll_popover(
 8994                |_| SCROLL_PADDING_Y,
 8995                IconName::ArrowUp,
 8996                visible_row_range,
 8997                line_layouts,
 8998                newest_selection_head,
 8999                scrolled_content_origin,
 9000                window,
 9001                cx,
 9002            );
 9003        } else if target_display_point.row() >= visible_row_range.end {
 9004            return self.render_edit_prediction_scroll_popover(
 9005                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9006                IconName::ArrowDown,
 9007                visible_row_range,
 9008                line_layouts,
 9009                newest_selection_head,
 9010                scrolled_content_origin,
 9011                window,
 9012                cx,
 9013            );
 9014        }
 9015
 9016        const POLE_WIDTH: Pixels = px(2.);
 9017
 9018        let line_layout =
 9019            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9020        let target_column = target_display_point.column() as usize;
 9021
 9022        let target_x = line_layout.x_for_index(target_column);
 9023        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9024            - scroll_pixel_position.y;
 9025
 9026        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9027
 9028        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9029        border_color.l += 0.001;
 9030
 9031        let mut element = v_flex()
 9032            .items_end()
 9033            .when(flag_on_right, |el| el.items_start())
 9034            .child(if flag_on_right {
 9035                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9036                    .rounded_bl(px(0.))
 9037                    .rounded_tl(px(0.))
 9038                    .border_l_2()
 9039                    .border_color(border_color)
 9040            } else {
 9041                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9042                    .rounded_br(px(0.))
 9043                    .rounded_tr(px(0.))
 9044                    .border_r_2()
 9045                    .border_color(border_color)
 9046            })
 9047            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9048            .into_any();
 9049
 9050        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9051
 9052        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9053            - point(
 9054                if flag_on_right {
 9055                    POLE_WIDTH
 9056                } else {
 9057                    size.width - POLE_WIDTH
 9058                },
 9059                size.height - line_height,
 9060            );
 9061
 9062        origin.x = origin.x.max(content_origin.x);
 9063
 9064        element.prepaint_at(origin, window, cx);
 9065
 9066        Some((element, origin))
 9067    }
 9068
 9069    fn render_edit_prediction_scroll_popover(
 9070        &mut self,
 9071        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9072        scroll_icon: IconName,
 9073        visible_row_range: Range<DisplayRow>,
 9074        line_layouts: &[LineWithInvisibles],
 9075        newest_selection_head: Option<DisplayPoint>,
 9076        scrolled_content_origin: gpui::Point<Pixels>,
 9077        window: &mut Window,
 9078        cx: &mut App,
 9079    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9080        let mut element = self
 9081            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9082            .into_any();
 9083
 9084        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9085
 9086        let cursor = newest_selection_head?;
 9087        let cursor_row_layout =
 9088            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9089        let cursor_column = cursor.column() as usize;
 9090
 9091        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9092
 9093        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9094
 9095        element.prepaint_at(origin, window, cx);
 9096        Some((element, origin))
 9097    }
 9098
 9099    fn render_edit_prediction_eager_jump_popover(
 9100        &mut self,
 9101        text_bounds: &Bounds<Pixels>,
 9102        content_origin: gpui::Point<Pixels>,
 9103        editor_snapshot: &EditorSnapshot,
 9104        visible_row_range: Range<DisplayRow>,
 9105        scroll_top: ScrollOffset,
 9106        scroll_bottom: ScrollOffset,
 9107        line_height: Pixels,
 9108        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9109        target_display_point: DisplayPoint,
 9110        editor_width: Pixels,
 9111        window: &mut Window,
 9112        cx: &mut App,
 9113    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9114        if target_display_point.row().as_f64() < scroll_top {
 9115            let mut element = self
 9116                .render_edit_prediction_line_popover(
 9117                    "Jump to Edit",
 9118                    Some(IconName::ArrowUp),
 9119                    window,
 9120                    cx,
 9121                )
 9122                .into_any();
 9123
 9124            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9125            let offset = point(
 9126                (text_bounds.size.width - size.width) / 2.,
 9127                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9128            );
 9129
 9130            let origin = text_bounds.origin + offset;
 9131            element.prepaint_at(origin, window, cx);
 9132            Some((element, origin))
 9133        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9134            let mut element = self
 9135                .render_edit_prediction_line_popover(
 9136                    "Jump to Edit",
 9137                    Some(IconName::ArrowDown),
 9138                    window,
 9139                    cx,
 9140                )
 9141                .into_any();
 9142
 9143            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9144            let offset = point(
 9145                (text_bounds.size.width - size.width) / 2.,
 9146                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9147            );
 9148
 9149            let origin = text_bounds.origin + offset;
 9150            element.prepaint_at(origin, window, cx);
 9151            Some((element, origin))
 9152        } else {
 9153            self.render_edit_prediction_end_of_line_popover(
 9154                "Jump to Edit",
 9155                editor_snapshot,
 9156                visible_row_range,
 9157                target_display_point,
 9158                line_height,
 9159                scroll_pixel_position,
 9160                content_origin,
 9161                editor_width,
 9162                window,
 9163                cx,
 9164            )
 9165        }
 9166    }
 9167
 9168    fn render_edit_prediction_end_of_line_popover(
 9169        self: &mut Editor,
 9170        label: &'static str,
 9171        editor_snapshot: &EditorSnapshot,
 9172        visible_row_range: Range<DisplayRow>,
 9173        target_display_point: DisplayPoint,
 9174        line_height: Pixels,
 9175        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9176        content_origin: gpui::Point<Pixels>,
 9177        editor_width: Pixels,
 9178        window: &mut Window,
 9179        cx: &mut App,
 9180    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9181        let target_line_end = DisplayPoint::new(
 9182            target_display_point.row(),
 9183            editor_snapshot.line_len(target_display_point.row()),
 9184        );
 9185
 9186        let mut element = self
 9187            .render_edit_prediction_line_popover(label, None, window, cx)
 9188            .into_any();
 9189
 9190        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9191
 9192        let line_origin =
 9193            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9194
 9195        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9196        let mut origin = start_point
 9197            + line_origin
 9198            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9199        origin.x = origin.x.max(content_origin.x);
 9200
 9201        let max_x = content_origin.x + editor_width - size.width;
 9202
 9203        if origin.x > max_x {
 9204            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9205
 9206            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9207                origin.y += offset;
 9208                IconName::ArrowUp
 9209            } else {
 9210                origin.y -= offset;
 9211                IconName::ArrowDown
 9212            };
 9213
 9214            element = self
 9215                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9216                .into_any();
 9217
 9218            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9219
 9220            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9221        }
 9222
 9223        element.prepaint_at(origin, window, cx);
 9224        Some((element, origin))
 9225    }
 9226
 9227    fn render_edit_prediction_diff_popover(
 9228        self: &Editor,
 9229        text_bounds: &Bounds<Pixels>,
 9230        content_origin: gpui::Point<Pixels>,
 9231        right_margin: Pixels,
 9232        editor_snapshot: &EditorSnapshot,
 9233        visible_row_range: Range<DisplayRow>,
 9234        line_layouts: &[LineWithInvisibles],
 9235        line_height: Pixels,
 9236        scroll_position: gpui::Point<ScrollOffset>,
 9237        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9238        newest_selection_head: Option<DisplayPoint>,
 9239        editor_width: Pixels,
 9240        style: &EditorStyle,
 9241        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9242        edit_preview: &Option<language::EditPreview>,
 9243        snapshot: &language::BufferSnapshot,
 9244        window: &mut Window,
 9245        cx: &mut App,
 9246    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9247        let edit_start = edits
 9248            .first()
 9249            .unwrap()
 9250            .0
 9251            .start
 9252            .to_display_point(editor_snapshot);
 9253        let edit_end = edits
 9254            .last()
 9255            .unwrap()
 9256            .0
 9257            .end
 9258            .to_display_point(editor_snapshot);
 9259
 9260        let is_visible = visible_row_range.contains(&edit_start.row())
 9261            || visible_row_range.contains(&edit_end.row());
 9262        if !is_visible {
 9263            return None;
 9264        }
 9265
 9266        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9267            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9268        } else {
 9269            // Fallback for providers without edit_preview
 9270            crate::edit_prediction_fallback_text(edits, cx)
 9271        };
 9272
 9273        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9274        let line_count = highlighted_edits.text.lines().count();
 9275
 9276        const BORDER_WIDTH: Pixels = px(1.);
 9277
 9278        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9279        let has_keybind = keybind.is_some();
 9280
 9281        let mut element = h_flex()
 9282            .items_start()
 9283            .child(
 9284                h_flex()
 9285                    .bg(cx.theme().colors().editor_background)
 9286                    .border(BORDER_WIDTH)
 9287                    .shadow_xs()
 9288                    .border_color(cx.theme().colors().border)
 9289                    .rounded_l_lg()
 9290                    .when(line_count > 1, |el| el.rounded_br_lg())
 9291                    .pr_1()
 9292                    .child(styled_text),
 9293            )
 9294            .child(
 9295                h_flex()
 9296                    .h(line_height + BORDER_WIDTH * 2.)
 9297                    .px_1p5()
 9298                    .gap_1()
 9299                    // Workaround: For some reason, there's a gap if we don't do this
 9300                    .ml(-BORDER_WIDTH)
 9301                    .shadow(vec![gpui::BoxShadow {
 9302                        color: gpui::black().opacity(0.05),
 9303                        offset: point(px(1.), px(1.)),
 9304                        blur_radius: px(2.),
 9305                        spread_radius: px(0.),
 9306                    }])
 9307                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9308                    .border(BORDER_WIDTH)
 9309                    .border_color(cx.theme().colors().border)
 9310                    .rounded_r_lg()
 9311                    .id("edit_prediction_diff_popover_keybind")
 9312                    .when(!has_keybind, |el| {
 9313                        let status_colors = cx.theme().status();
 9314
 9315                        el.bg(status_colors.error_background)
 9316                            .border_color(status_colors.error.opacity(0.6))
 9317                            .child(Icon::new(IconName::Info).color(Color::Error))
 9318                            .cursor_default()
 9319                            .hoverable_tooltip(move |_window, cx| {
 9320                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9321                            })
 9322                    })
 9323                    .children(keybind),
 9324            )
 9325            .into_any();
 9326
 9327        let longest_row =
 9328            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9329        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9330            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9331        } else {
 9332            layout_line(
 9333                longest_row,
 9334                editor_snapshot,
 9335                style,
 9336                editor_width,
 9337                |_| false,
 9338                window,
 9339                cx,
 9340            )
 9341            .width
 9342        };
 9343
 9344        let viewport_bounds =
 9345            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9346                right: -right_margin,
 9347                ..Default::default()
 9348            });
 9349
 9350        let x_after_longest = Pixels::from(
 9351            ScrollPixelOffset::from(
 9352                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9353            ) - scroll_pixel_position.x,
 9354        );
 9355
 9356        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9357
 9358        // Fully visible if it can be displayed within the window (allow overlapping other
 9359        // panes). However, this is only allowed if the popover starts within text_bounds.
 9360        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9361            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9362
 9363        let mut origin = if can_position_to_the_right {
 9364            point(
 9365                x_after_longest,
 9366                text_bounds.origin.y
 9367                    + Pixels::from(
 9368                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9369                            - scroll_pixel_position.y,
 9370                    ),
 9371            )
 9372        } else {
 9373            let cursor_row = newest_selection_head.map(|head| head.row());
 9374            let above_edit = edit_start
 9375                .row()
 9376                .0
 9377                .checked_sub(line_count as u32)
 9378                .map(DisplayRow);
 9379            let below_edit = Some(edit_end.row() + 1);
 9380            let above_cursor =
 9381                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9382            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9383
 9384            // Place the edit popover adjacent to the edit if there is a location
 9385            // available that is onscreen and does not obscure the cursor. Otherwise,
 9386            // place it adjacent to the cursor.
 9387            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9388                .into_iter()
 9389                .flatten()
 9390                .find(|&start_row| {
 9391                    let end_row = start_row + line_count as u32;
 9392                    visible_row_range.contains(&start_row)
 9393                        && visible_row_range.contains(&end_row)
 9394                        && cursor_row
 9395                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9396                })?;
 9397
 9398            content_origin
 9399                + point(
 9400                    Pixels::from(-scroll_pixel_position.x),
 9401                    Pixels::from(
 9402                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9403                    ),
 9404                )
 9405        };
 9406
 9407        origin.x -= BORDER_WIDTH;
 9408
 9409        window.defer_draw(element, origin, 1);
 9410
 9411        // Do not return an element, since it will already be drawn due to defer_draw.
 9412        None
 9413    }
 9414
 9415    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9416        px(30.)
 9417    }
 9418
 9419    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9420        if self.read_only(cx) {
 9421            cx.theme().players().read_only()
 9422        } else {
 9423            self.style.as_ref().unwrap().local_player
 9424        }
 9425    }
 9426
 9427    fn render_edit_prediction_accept_keybind(
 9428        &self,
 9429        window: &mut Window,
 9430        cx: &mut App,
 9431    ) -> Option<AnyElement> {
 9432        let accept_binding =
 9433            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9434        let accept_keystroke = accept_binding.keystroke()?;
 9435
 9436        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9437
 9438        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9439            Color::Accent
 9440        } else {
 9441            Color::Muted
 9442        };
 9443
 9444        h_flex()
 9445            .px_0p5()
 9446            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9447            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9448            .text_size(TextSize::XSmall.rems(cx))
 9449            .child(h_flex().children(ui::render_modifiers(
 9450                accept_keystroke.modifiers(),
 9451                PlatformStyle::platform(),
 9452                Some(modifiers_color),
 9453                Some(IconSize::XSmall.rems().into()),
 9454                true,
 9455            )))
 9456            .when(is_platform_style_mac, |parent| {
 9457                parent.child(accept_keystroke.key().to_string())
 9458            })
 9459            .when(!is_platform_style_mac, |parent| {
 9460                parent.child(
 9461                    Key::new(
 9462                        util::capitalize(accept_keystroke.key()),
 9463                        Some(Color::Default),
 9464                    )
 9465                    .size(Some(IconSize::XSmall.rems().into())),
 9466                )
 9467            })
 9468            .into_any()
 9469            .into()
 9470    }
 9471
 9472    fn render_edit_prediction_line_popover(
 9473        &self,
 9474        label: impl Into<SharedString>,
 9475        icon: Option<IconName>,
 9476        window: &mut Window,
 9477        cx: &mut App,
 9478    ) -> Stateful<Div> {
 9479        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9480
 9481        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9482        let has_keybind = keybind.is_some();
 9483
 9484        h_flex()
 9485            .id("ep-line-popover")
 9486            .py_0p5()
 9487            .pl_1()
 9488            .pr(padding_right)
 9489            .gap_1()
 9490            .rounded_md()
 9491            .border_1()
 9492            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9493            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9494            .shadow_xs()
 9495            .when(!has_keybind, |el| {
 9496                let status_colors = cx.theme().status();
 9497
 9498                el.bg(status_colors.error_background)
 9499                    .border_color(status_colors.error.opacity(0.6))
 9500                    .pl_2()
 9501                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9502                    .cursor_default()
 9503                    .hoverable_tooltip(move |_window, cx| {
 9504                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9505                    })
 9506            })
 9507            .children(keybind)
 9508            .child(
 9509                Label::new(label)
 9510                    .size(LabelSize::Small)
 9511                    .when(!has_keybind, |el| {
 9512                        el.color(cx.theme().status().error.into()).strikethrough()
 9513                    }),
 9514            )
 9515            .when(!has_keybind, |el| {
 9516                el.child(
 9517                    h_flex().ml_1().child(
 9518                        Icon::new(IconName::Info)
 9519                            .size(IconSize::Small)
 9520                            .color(cx.theme().status().error.into()),
 9521                    ),
 9522                )
 9523            })
 9524            .when_some(icon, |element, icon| {
 9525                element.child(
 9526                    div()
 9527                        .mt(px(1.5))
 9528                        .child(Icon::new(icon).size(IconSize::Small)),
 9529                )
 9530            })
 9531    }
 9532
 9533    fn render_edit_prediction_jump_outside_popover(
 9534        &self,
 9535        snapshot: &BufferSnapshot,
 9536        window: &mut Window,
 9537        cx: &mut App,
 9538    ) -> Stateful<Div> {
 9539        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9540        let has_keybind = keybind.is_some();
 9541
 9542        let file_name = snapshot
 9543            .file()
 9544            .map(|file| SharedString::new(file.file_name(cx)))
 9545            .unwrap_or(SharedString::new_static("untitled"));
 9546
 9547        h_flex()
 9548            .id("ep-jump-outside-popover")
 9549            .py_1()
 9550            .px_2()
 9551            .gap_1()
 9552            .rounded_md()
 9553            .border_1()
 9554            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9555            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9556            .shadow_xs()
 9557            .when(!has_keybind, |el| {
 9558                let status_colors = cx.theme().status();
 9559
 9560                el.bg(status_colors.error_background)
 9561                    .border_color(status_colors.error.opacity(0.6))
 9562                    .pl_2()
 9563                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9564                    .cursor_default()
 9565                    .hoverable_tooltip(move |_window, cx| {
 9566                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9567                    })
 9568            })
 9569            .children(keybind)
 9570            .child(
 9571                Label::new(file_name)
 9572                    .size(LabelSize::Small)
 9573                    .buffer_font(cx)
 9574                    .when(!has_keybind, |el| {
 9575                        el.color(cx.theme().status().error.into()).strikethrough()
 9576                    }),
 9577            )
 9578            .when(!has_keybind, |el| {
 9579                el.child(
 9580                    h_flex().ml_1().child(
 9581                        Icon::new(IconName::Info)
 9582                            .size(IconSize::Small)
 9583                            .color(cx.theme().status().error.into()),
 9584                    ),
 9585                )
 9586            })
 9587            .child(
 9588                div()
 9589                    .mt(px(1.5))
 9590                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9591            )
 9592    }
 9593
 9594    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9595        let accent_color = cx.theme().colors().text_accent;
 9596        let editor_bg_color = cx.theme().colors().editor_background;
 9597        editor_bg_color.blend(accent_color.opacity(0.1))
 9598    }
 9599
 9600    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9601        let accent_color = cx.theme().colors().text_accent;
 9602        let editor_bg_color = cx.theme().colors().editor_background;
 9603        editor_bg_color.blend(accent_color.opacity(0.6))
 9604    }
 9605    fn get_prediction_provider_icon_name(
 9606        provider: &Option<RegisteredEditPredictionDelegate>,
 9607    ) -> IconName {
 9608        match provider {
 9609            Some(provider) => match provider.provider.name() {
 9610                "copilot" => IconName::Copilot,
 9611                "supermaven" => IconName::Supermaven,
 9612                _ => IconName::ZedPredict,
 9613            },
 9614            None => IconName::ZedPredict,
 9615        }
 9616    }
 9617
 9618    fn render_edit_prediction_cursor_popover(
 9619        &self,
 9620        min_width: Pixels,
 9621        max_width: Pixels,
 9622        cursor_point: Point,
 9623        style: &EditorStyle,
 9624        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9625        _window: &Window,
 9626        cx: &mut Context<Editor>,
 9627    ) -> Option<AnyElement> {
 9628        let provider = self.edit_prediction_provider.as_ref()?;
 9629        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9630
 9631        let is_refreshing = provider.provider.is_refreshing(cx);
 9632
 9633        fn pending_completion_container(icon: IconName) -> Div {
 9634            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9635        }
 9636
 9637        let completion = match &self.active_edit_prediction {
 9638            Some(prediction) => {
 9639                if !self.has_visible_completions_menu() {
 9640                    const RADIUS: Pixels = px(6.);
 9641                    const BORDER_WIDTH: Pixels = px(1.);
 9642
 9643                    return Some(
 9644                        h_flex()
 9645                            .elevation_2(cx)
 9646                            .border(BORDER_WIDTH)
 9647                            .border_color(cx.theme().colors().border)
 9648                            .when(accept_keystroke.is_none(), |el| {
 9649                                el.border_color(cx.theme().status().error)
 9650                            })
 9651                            .rounded(RADIUS)
 9652                            .rounded_tl(px(0.))
 9653                            .overflow_hidden()
 9654                            .child(div().px_1p5().child(match &prediction.completion {
 9655                                EditPrediction::MoveWithin { target, snapshot } => {
 9656                                    use text::ToPoint as _;
 9657                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9658                                    {
 9659                                        Icon::new(IconName::ZedPredictDown)
 9660                                    } else {
 9661                                        Icon::new(IconName::ZedPredictUp)
 9662                                    }
 9663                                }
 9664                                EditPrediction::MoveOutside { .. } => {
 9665                                    // TODO [zeta2] custom icon for external jump?
 9666                                    Icon::new(provider_icon)
 9667                                }
 9668                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9669                            }))
 9670                            .child(
 9671                                h_flex()
 9672                                    .gap_1()
 9673                                    .py_1()
 9674                                    .px_2()
 9675                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9676                                    .border_l_1()
 9677                                    .border_color(cx.theme().colors().border)
 9678                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9679                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9680                                        el.child(
 9681                                            Label::new("Hold")
 9682                                                .size(LabelSize::Small)
 9683                                                .when(accept_keystroke.is_none(), |el| {
 9684                                                    el.strikethrough()
 9685                                                })
 9686                                                .line_height_style(LineHeightStyle::UiLabel),
 9687                                        )
 9688                                    })
 9689                                    .id("edit_prediction_cursor_popover_keybind")
 9690                                    .when(accept_keystroke.is_none(), |el| {
 9691                                        let status_colors = cx.theme().status();
 9692
 9693                                        el.bg(status_colors.error_background)
 9694                                            .border_color(status_colors.error.opacity(0.6))
 9695                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9696                                            .cursor_default()
 9697                                            .hoverable_tooltip(move |_window, cx| {
 9698                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9699                                                    .into()
 9700                                            })
 9701                                    })
 9702                                    .when_some(
 9703                                        accept_keystroke.as_ref(),
 9704                                        |el, accept_keystroke| {
 9705                                            el.child(h_flex().children(ui::render_modifiers(
 9706                                                accept_keystroke.modifiers(),
 9707                                                PlatformStyle::platform(),
 9708                                                Some(Color::Default),
 9709                                                Some(IconSize::XSmall.rems().into()),
 9710                                                false,
 9711                                            )))
 9712                                        },
 9713                                    ),
 9714                            )
 9715                            .into_any(),
 9716                    );
 9717                }
 9718
 9719                self.render_edit_prediction_cursor_popover_preview(
 9720                    prediction,
 9721                    cursor_point,
 9722                    style,
 9723                    cx,
 9724                )?
 9725            }
 9726
 9727            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9728                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9729                    stale_completion,
 9730                    cursor_point,
 9731                    style,
 9732                    cx,
 9733                )?,
 9734
 9735                None => pending_completion_container(provider_icon)
 9736                    .child(Label::new("...").size(LabelSize::Small)),
 9737            },
 9738
 9739            None => pending_completion_container(provider_icon)
 9740                .child(Label::new("...").size(LabelSize::Small)),
 9741        };
 9742
 9743        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9744            completion
 9745                .with_animation(
 9746                    "loading-completion",
 9747                    Animation::new(Duration::from_secs(2))
 9748                        .repeat()
 9749                        .with_easing(pulsating_between(0.4, 0.8)),
 9750                    |label, delta| label.opacity(delta),
 9751                )
 9752                .into_any_element()
 9753        } else {
 9754            completion.into_any_element()
 9755        };
 9756
 9757        let has_completion = self.active_edit_prediction.is_some();
 9758
 9759        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9760        Some(
 9761            h_flex()
 9762                .min_w(min_width)
 9763                .max_w(max_width)
 9764                .flex_1()
 9765                .elevation_2(cx)
 9766                .border_color(cx.theme().colors().border)
 9767                .child(
 9768                    div()
 9769                        .flex_1()
 9770                        .py_1()
 9771                        .px_2()
 9772                        .overflow_hidden()
 9773                        .child(completion),
 9774                )
 9775                .when_some(accept_keystroke, |el, accept_keystroke| {
 9776                    if !accept_keystroke.modifiers().modified() {
 9777                        return el;
 9778                    }
 9779
 9780                    el.child(
 9781                        h_flex()
 9782                            .h_full()
 9783                            .border_l_1()
 9784                            .rounded_r_lg()
 9785                            .border_color(cx.theme().colors().border)
 9786                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9787                            .gap_1()
 9788                            .py_1()
 9789                            .px_2()
 9790                            .child(
 9791                                h_flex()
 9792                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9793                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9794                                    .child(h_flex().children(ui::render_modifiers(
 9795                                        accept_keystroke.modifiers(),
 9796                                        PlatformStyle::platform(),
 9797                                        Some(if !has_completion {
 9798                                            Color::Muted
 9799                                        } else {
 9800                                            Color::Default
 9801                                        }),
 9802                                        None,
 9803                                        false,
 9804                                    ))),
 9805                            )
 9806                            .child(Label::new("Preview").into_any_element())
 9807                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9808                    )
 9809                })
 9810                .into_any(),
 9811        )
 9812    }
 9813
 9814    fn render_edit_prediction_cursor_popover_preview(
 9815        &self,
 9816        completion: &EditPredictionState,
 9817        cursor_point: Point,
 9818        style: &EditorStyle,
 9819        cx: &mut Context<Editor>,
 9820    ) -> Option<Div> {
 9821        use text::ToPoint as _;
 9822
 9823        fn render_relative_row_jump(
 9824            prefix: impl Into<String>,
 9825            current_row: u32,
 9826            target_row: u32,
 9827        ) -> Div {
 9828            let (row_diff, arrow) = if target_row < current_row {
 9829                (current_row - target_row, IconName::ArrowUp)
 9830            } else {
 9831                (target_row - current_row, IconName::ArrowDown)
 9832            };
 9833
 9834            h_flex()
 9835                .child(
 9836                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9837                        .color(Color::Muted)
 9838                        .size(LabelSize::Small),
 9839                )
 9840                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9841        }
 9842
 9843        let supports_jump = self
 9844            .edit_prediction_provider
 9845            .as_ref()
 9846            .map(|provider| provider.provider.supports_jump_to_edit())
 9847            .unwrap_or(true);
 9848
 9849        match &completion.completion {
 9850            EditPrediction::MoveWithin {
 9851                target, snapshot, ..
 9852            } => {
 9853                if !supports_jump {
 9854                    return None;
 9855                }
 9856
 9857                Some(
 9858                    h_flex()
 9859                        .px_2()
 9860                        .gap_2()
 9861                        .flex_1()
 9862                        .child(
 9863                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9864                                Icon::new(IconName::ZedPredictDown)
 9865                            } else {
 9866                                Icon::new(IconName::ZedPredictUp)
 9867                            },
 9868                        )
 9869                        .child(Label::new("Jump to Edit")),
 9870                )
 9871            }
 9872            EditPrediction::MoveOutside { snapshot, .. } => {
 9873                let file_name = snapshot
 9874                    .file()
 9875                    .map(|file| file.file_name(cx))
 9876                    .unwrap_or("untitled");
 9877                Some(
 9878                    h_flex()
 9879                        .px_2()
 9880                        .gap_2()
 9881                        .flex_1()
 9882                        .child(Icon::new(IconName::ZedPredict))
 9883                        .child(Label::new(format!("Jump to {file_name}"))),
 9884                )
 9885            }
 9886            EditPrediction::Edit {
 9887                edits,
 9888                edit_preview,
 9889                snapshot,
 9890                display_mode: _,
 9891            } => {
 9892                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9893
 9894                let (highlighted_edits, has_more_lines) =
 9895                    if let Some(edit_preview) = edit_preview.as_ref() {
 9896                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9897                            .first_line_preview()
 9898                    } else {
 9899                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9900                    };
 9901
 9902                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9903                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9904
 9905                let preview = h_flex()
 9906                    .gap_1()
 9907                    .min_w_16()
 9908                    .child(styled_text)
 9909                    .when(has_more_lines, |parent| parent.child(""));
 9910
 9911                let left = if supports_jump && first_edit_row != cursor_point.row {
 9912                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9913                        .into_any_element()
 9914                } else {
 9915                    let icon_name =
 9916                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9917                    Icon::new(icon_name).into_any_element()
 9918                };
 9919
 9920                Some(
 9921                    h_flex()
 9922                        .h_full()
 9923                        .flex_1()
 9924                        .gap_2()
 9925                        .pr_1()
 9926                        .overflow_x_hidden()
 9927                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9928                        .child(left)
 9929                        .child(preview),
 9930                )
 9931            }
 9932        }
 9933    }
 9934
 9935    pub fn render_context_menu(
 9936        &mut self,
 9937        max_height_in_lines: u32,
 9938        window: &mut Window,
 9939        cx: &mut Context<Editor>,
 9940    ) -> Option<AnyElement> {
 9941        let menu = self.context_menu.borrow();
 9942        let menu = menu.as_ref()?;
 9943        if !menu.visible() {
 9944            return None;
 9945        };
 9946        self.style
 9947            .as_ref()
 9948            .map(|style| menu.render(style, max_height_in_lines, window, cx))
 9949    }
 9950
 9951    fn render_context_menu_aside(
 9952        &mut self,
 9953        max_size: Size<Pixels>,
 9954        window: &mut Window,
 9955        cx: &mut Context<Editor>,
 9956    ) -> Option<AnyElement> {
 9957        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9958            if menu.visible() {
 9959                menu.render_aside(max_size, window, cx)
 9960            } else {
 9961                None
 9962            }
 9963        })
 9964    }
 9965
 9966    fn hide_context_menu(
 9967        &mut self,
 9968        window: &mut Window,
 9969        cx: &mut Context<Self>,
 9970    ) -> Option<CodeContextMenu> {
 9971        cx.notify();
 9972        self.completion_tasks.clear();
 9973        let context_menu = self.context_menu.borrow_mut().take();
 9974        self.stale_edit_prediction_in_menu.take();
 9975        self.update_visible_edit_prediction(window, cx);
 9976        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9977            && let Some(completion_provider) = &self.completion_provider
 9978        {
 9979            completion_provider.selection_changed(None, window, cx);
 9980        }
 9981        context_menu
 9982    }
 9983
 9984    fn show_snippet_choices(
 9985        &mut self,
 9986        choices: &Vec<String>,
 9987        selection: Range<Anchor>,
 9988        cx: &mut Context<Self>,
 9989    ) {
 9990        let Some((_, buffer, _)) = self
 9991            .buffer()
 9992            .read(cx)
 9993            .excerpt_containing(selection.start, cx)
 9994        else {
 9995            return;
 9996        };
 9997        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9998        else {
 9999            return;
10000        };
10001        if buffer != end_buffer {
10002            log::error!("expected anchor range to have matching buffer IDs");
10003            return;
10004        }
10005
10006        let id = post_inc(&mut self.next_completion_id);
10007        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10008        let mut context_menu = self.context_menu.borrow_mut();
10009        let old_menu = context_menu.take();
10010        *context_menu = Some(CodeContextMenu::Completions(
10011            CompletionsMenu::new_snippet_choices(
10012                id,
10013                true,
10014                choices,
10015                selection,
10016                buffer,
10017                old_menu.map(|menu| menu.primary_scroll_handle()),
10018                snippet_sort_order,
10019            ),
10020        ));
10021    }
10022
10023    pub fn insert_snippet(
10024        &mut self,
10025        insertion_ranges: &[Range<MultiBufferOffset>],
10026        snippet: Snippet,
10027        window: &mut Window,
10028        cx: &mut Context<Self>,
10029    ) -> Result<()> {
10030        struct Tabstop<T> {
10031            is_end_tabstop: bool,
10032            ranges: Vec<Range<T>>,
10033            choices: Option<Vec<String>>,
10034        }
10035
10036        let tabstops = self.buffer.update(cx, |buffer, cx| {
10037            let snippet_text: Arc<str> = snippet.text.clone().into();
10038            let edits = insertion_ranges
10039                .iter()
10040                .cloned()
10041                .map(|range| (range, snippet_text.clone()));
10042            let autoindent_mode = AutoindentMode::Block {
10043                original_indent_columns: Vec::new(),
10044            };
10045            buffer.edit(edits, Some(autoindent_mode), cx);
10046
10047            let snapshot = &*buffer.read(cx);
10048            let snippet = &snippet;
10049            snippet
10050                .tabstops
10051                .iter()
10052                .map(|tabstop| {
10053                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10054                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10055                    });
10056                    let mut tabstop_ranges = tabstop
10057                        .ranges
10058                        .iter()
10059                        .flat_map(|tabstop_range| {
10060                            let mut delta = 0_isize;
10061                            insertion_ranges.iter().map(move |insertion_range| {
10062                                let insertion_start = insertion_range.start + delta;
10063                                delta += snippet.text.len() as isize
10064                                    - (insertion_range.end - insertion_range.start) as isize;
10065
10066                                let start =
10067                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10068                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10069                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10070                            })
10071                        })
10072                        .collect::<Vec<_>>();
10073                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10074
10075                    Tabstop {
10076                        is_end_tabstop,
10077                        ranges: tabstop_ranges,
10078                        choices: tabstop.choices.clone(),
10079                    }
10080                })
10081                .collect::<Vec<_>>()
10082        });
10083        if let Some(tabstop) = tabstops.first() {
10084            self.change_selections(Default::default(), window, cx, |s| {
10085                // Reverse order so that the first range is the newest created selection.
10086                // Completions will use it and autoscroll will prioritize it.
10087                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10088            });
10089
10090            if let Some(choices) = &tabstop.choices
10091                && let Some(selection) = tabstop.ranges.first()
10092            {
10093                self.show_snippet_choices(choices, selection.clone(), cx)
10094            }
10095
10096            // If we're already at the last tabstop and it's at the end of the snippet,
10097            // we're done, we don't need to keep the state around.
10098            if !tabstop.is_end_tabstop {
10099                let choices = tabstops
10100                    .iter()
10101                    .map(|tabstop| tabstop.choices.clone())
10102                    .collect();
10103
10104                let ranges = tabstops
10105                    .into_iter()
10106                    .map(|tabstop| tabstop.ranges)
10107                    .collect::<Vec<_>>();
10108
10109                self.snippet_stack.push(SnippetState {
10110                    active_index: 0,
10111                    ranges,
10112                    choices,
10113                });
10114            }
10115
10116            // Check whether the just-entered snippet ends with an auto-closable bracket.
10117            if self.autoclose_regions.is_empty() {
10118                let snapshot = self.buffer.read(cx).snapshot(cx);
10119                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10120                    let selection_head = selection.head();
10121                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10122                        continue;
10123                    };
10124
10125                    let mut bracket_pair = None;
10126                    let max_lookup_length = scope
10127                        .brackets()
10128                        .map(|(pair, _)| {
10129                            pair.start
10130                                .as_str()
10131                                .chars()
10132                                .count()
10133                                .max(pair.end.as_str().chars().count())
10134                        })
10135                        .max();
10136                    if let Some(max_lookup_length) = max_lookup_length {
10137                        let next_text = snapshot
10138                            .chars_at(selection_head)
10139                            .take(max_lookup_length)
10140                            .collect::<String>();
10141                        let prev_text = snapshot
10142                            .reversed_chars_at(selection_head)
10143                            .take(max_lookup_length)
10144                            .collect::<String>();
10145
10146                        for (pair, enabled) in scope.brackets() {
10147                            if enabled
10148                                && pair.close
10149                                && prev_text.starts_with(pair.start.as_str())
10150                                && next_text.starts_with(pair.end.as_str())
10151                            {
10152                                bracket_pair = Some(pair.clone());
10153                                break;
10154                            }
10155                        }
10156                    }
10157
10158                    if let Some(pair) = bracket_pair {
10159                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10160                        let autoclose_enabled =
10161                            self.use_autoclose && snapshot_settings.use_autoclose;
10162                        if autoclose_enabled {
10163                            let start = snapshot.anchor_after(selection_head);
10164                            let end = snapshot.anchor_after(selection_head);
10165                            self.autoclose_regions.push(AutocloseRegion {
10166                                selection_id: selection.id,
10167                                range: start..end,
10168                                pair,
10169                            });
10170                        }
10171                    }
10172                }
10173            }
10174        }
10175        Ok(())
10176    }
10177
10178    pub fn move_to_next_snippet_tabstop(
10179        &mut self,
10180        window: &mut Window,
10181        cx: &mut Context<Self>,
10182    ) -> bool {
10183        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10184    }
10185
10186    pub fn move_to_prev_snippet_tabstop(
10187        &mut self,
10188        window: &mut Window,
10189        cx: &mut Context<Self>,
10190    ) -> bool {
10191        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10192    }
10193
10194    pub fn move_to_snippet_tabstop(
10195        &mut self,
10196        bias: Bias,
10197        window: &mut Window,
10198        cx: &mut Context<Self>,
10199    ) -> bool {
10200        if let Some(mut snippet) = self.snippet_stack.pop() {
10201            match bias {
10202                Bias::Left => {
10203                    if snippet.active_index > 0 {
10204                        snippet.active_index -= 1;
10205                    } else {
10206                        self.snippet_stack.push(snippet);
10207                        return false;
10208                    }
10209                }
10210                Bias::Right => {
10211                    if snippet.active_index + 1 < snippet.ranges.len() {
10212                        snippet.active_index += 1;
10213                    } else {
10214                        self.snippet_stack.push(snippet);
10215                        return false;
10216                    }
10217                }
10218            }
10219            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10220                self.change_selections(Default::default(), window, cx, |s| {
10221                    // Reverse order so that the first range is the newest created selection.
10222                    // Completions will use it and autoscroll will prioritize it.
10223                    s.select_ranges(current_ranges.iter().rev().cloned())
10224                });
10225
10226                if let Some(choices) = &snippet.choices[snippet.active_index]
10227                    && let Some(selection) = current_ranges.first()
10228                {
10229                    self.show_snippet_choices(choices, selection.clone(), cx);
10230                }
10231
10232                // If snippet state is not at the last tabstop, push it back on the stack
10233                if snippet.active_index + 1 < snippet.ranges.len() {
10234                    self.snippet_stack.push(snippet);
10235                }
10236                return true;
10237            }
10238        }
10239
10240        false
10241    }
10242
10243    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10244        self.transact(window, cx, |this, window, cx| {
10245            this.select_all(&SelectAll, window, cx);
10246            this.insert("", window, cx);
10247        });
10248    }
10249
10250    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10251        if self.read_only(cx) {
10252            return;
10253        }
10254        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10255        self.transact(window, cx, |this, window, cx| {
10256            this.select_autoclose_pair(window, cx);
10257
10258            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10259
10260            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10261            if !this.linked_edit_ranges.is_empty() {
10262                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10263                let snapshot = this.buffer.read(cx).snapshot(cx);
10264
10265                for selection in selections.iter() {
10266                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10267                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10268                    if selection_start.buffer_id != selection_end.buffer_id {
10269                        continue;
10270                    }
10271                    if let Some(ranges) =
10272                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10273                    {
10274                        for (buffer, entries) in ranges {
10275                            linked_ranges.entry(buffer).or_default().extend(entries);
10276                        }
10277                    }
10278                }
10279            }
10280
10281            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10282            for selection in &mut selections {
10283                if selection.is_empty() {
10284                    let old_head = selection.head();
10285                    let mut new_head =
10286                        movement::left(&display_map, old_head.to_display_point(&display_map))
10287                            .to_point(&display_map);
10288                    if let Some((buffer, line_buffer_range)) = display_map
10289                        .buffer_snapshot()
10290                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10291                    {
10292                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10293                        let indent_len = match indent_size.kind {
10294                            IndentKind::Space => {
10295                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10296                            }
10297                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10298                        };
10299                        if old_head.column <= indent_size.len && old_head.column > 0 {
10300                            let indent_len = indent_len.get();
10301                            new_head = cmp::min(
10302                                new_head,
10303                                MultiBufferPoint::new(
10304                                    old_head.row,
10305                                    ((old_head.column - 1) / indent_len) * indent_len,
10306                                ),
10307                            );
10308                        }
10309                    }
10310
10311                    selection.set_head(new_head, SelectionGoal::None);
10312                }
10313            }
10314
10315            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10316            this.insert("", window, cx);
10317            let empty_str: Arc<str> = Arc::from("");
10318            for (buffer, edits) in linked_ranges {
10319                let snapshot = buffer.read(cx).snapshot();
10320                use text::ToPoint as TP;
10321
10322                let edits = edits
10323                    .into_iter()
10324                    .map(|range| {
10325                        let end_point = TP::to_point(&range.end, &snapshot);
10326                        let mut start_point = TP::to_point(&range.start, &snapshot);
10327
10328                        if end_point == start_point {
10329                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10330                                .saturating_sub(1);
10331                            start_point =
10332                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10333                        };
10334
10335                        (start_point..end_point, empty_str.clone())
10336                    })
10337                    .sorted_by_key(|(range, _)| range.start)
10338                    .collect::<Vec<_>>();
10339                buffer.update(cx, |this, cx| {
10340                    this.edit(edits, None, cx);
10341                })
10342            }
10343            this.refresh_edit_prediction(true, false, window, cx);
10344            refresh_linked_ranges(this, window, cx);
10345        });
10346    }
10347
10348    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10349        if self.read_only(cx) {
10350            return;
10351        }
10352        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10353        self.transact(window, cx, |this, window, cx| {
10354            this.change_selections(Default::default(), window, cx, |s| {
10355                s.move_with(|map, selection| {
10356                    if selection.is_empty() {
10357                        let cursor = movement::right(map, selection.head());
10358                        selection.end = cursor;
10359                        selection.reversed = true;
10360                        selection.goal = SelectionGoal::None;
10361                    }
10362                })
10363            });
10364            this.insert("", window, cx);
10365            this.refresh_edit_prediction(true, false, window, cx);
10366        });
10367    }
10368
10369    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10370        if self.mode.is_single_line() {
10371            cx.propagate();
10372            return;
10373        }
10374
10375        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10376        if self.move_to_prev_snippet_tabstop(window, cx) {
10377            return;
10378        }
10379        self.outdent(&Outdent, window, cx);
10380    }
10381
10382    pub fn next_snippet_tabstop(
10383        &mut self,
10384        _: &NextSnippetTabstop,
10385        window: &mut Window,
10386        cx: &mut Context<Self>,
10387    ) {
10388        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10389            cx.propagate();
10390            return;
10391        }
10392
10393        if self.move_to_next_snippet_tabstop(window, cx) {
10394            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10395            return;
10396        }
10397        cx.propagate();
10398    }
10399
10400    pub fn previous_snippet_tabstop(
10401        &mut self,
10402        _: &PreviousSnippetTabstop,
10403        window: &mut Window,
10404        cx: &mut Context<Self>,
10405    ) {
10406        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10407            cx.propagate();
10408            return;
10409        }
10410
10411        if self.move_to_prev_snippet_tabstop(window, cx) {
10412            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10413            return;
10414        }
10415        cx.propagate();
10416    }
10417
10418    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10419        if self.mode.is_single_line() {
10420            cx.propagate();
10421            return;
10422        }
10423
10424        if self.move_to_next_snippet_tabstop(window, cx) {
10425            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10426            return;
10427        }
10428        if self.read_only(cx) {
10429            return;
10430        }
10431        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10432        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10433        let buffer = self.buffer.read(cx);
10434        let snapshot = buffer.snapshot(cx);
10435        let rows_iter = selections.iter().map(|s| s.head().row);
10436        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10437
10438        let has_some_cursor_in_whitespace = selections
10439            .iter()
10440            .filter(|selection| selection.is_empty())
10441            .any(|selection| {
10442                let cursor = selection.head();
10443                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10444                cursor.column < current_indent.len
10445            });
10446
10447        let mut edits = Vec::new();
10448        let mut prev_edited_row = 0;
10449        let mut row_delta = 0;
10450        for selection in &mut selections {
10451            if selection.start.row != prev_edited_row {
10452                row_delta = 0;
10453            }
10454            prev_edited_row = selection.end.row;
10455
10456            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10457            if selection.is_empty() {
10458                let cursor = selection.head();
10459                let settings = buffer.language_settings_at(cursor, cx);
10460                if settings.indent_list_on_tab {
10461                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10462                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10463                            row_delta = Self::indent_selection(
10464                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10465                            );
10466                            continue;
10467                        }
10468                    }
10469                }
10470            }
10471
10472            // If the selection is non-empty, then increase the indentation of the selected lines.
10473            if !selection.is_empty() {
10474                row_delta =
10475                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10476                continue;
10477            }
10478
10479            let cursor = selection.head();
10480            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10481            if let Some(suggested_indent) =
10482                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10483            {
10484                // Don't do anything if already at suggested indent
10485                // and there is any other cursor which is not
10486                if has_some_cursor_in_whitespace
10487                    && cursor.column == current_indent.len
10488                    && current_indent.len == suggested_indent.len
10489                {
10490                    continue;
10491                }
10492
10493                // Adjust line and move cursor to suggested indent
10494                // if cursor is not at suggested indent
10495                if cursor.column < suggested_indent.len
10496                    && cursor.column <= current_indent.len
10497                    && current_indent.len <= suggested_indent.len
10498                {
10499                    selection.start = Point::new(cursor.row, suggested_indent.len);
10500                    selection.end = selection.start;
10501                    if row_delta == 0 {
10502                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10503                            cursor.row,
10504                            current_indent,
10505                            suggested_indent,
10506                        ));
10507                        row_delta = suggested_indent.len - current_indent.len;
10508                    }
10509                    continue;
10510                }
10511
10512                // If current indent is more than suggested indent
10513                // only move cursor to current indent and skip indent
10514                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10515                    selection.start = Point::new(cursor.row, current_indent.len);
10516                    selection.end = selection.start;
10517                    continue;
10518                }
10519            }
10520
10521            // Otherwise, insert a hard or soft tab.
10522            let settings = buffer.language_settings_at(cursor, cx);
10523            let tab_size = if settings.hard_tabs {
10524                IndentSize::tab()
10525            } else {
10526                let tab_size = settings.tab_size.get();
10527                let indent_remainder = snapshot
10528                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10529                    .flat_map(str::chars)
10530                    .fold(row_delta % tab_size, |counter: u32, c| {
10531                        if c == '\t' {
10532                            0
10533                        } else {
10534                            (counter + 1) % tab_size
10535                        }
10536                    });
10537
10538                let chars_to_next_tab_stop = tab_size - indent_remainder;
10539                IndentSize::spaces(chars_to_next_tab_stop)
10540            };
10541            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10542            selection.end = selection.start;
10543            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10544            row_delta += tab_size.len;
10545        }
10546
10547        self.transact(window, cx, |this, window, cx| {
10548            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10549            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10550            this.refresh_edit_prediction(true, false, window, cx);
10551        });
10552    }
10553
10554    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10555        if self.read_only(cx) {
10556            return;
10557        }
10558        if self.mode.is_single_line() {
10559            cx.propagate();
10560            return;
10561        }
10562
10563        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10564        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10565        let mut prev_edited_row = 0;
10566        let mut row_delta = 0;
10567        let mut edits = Vec::new();
10568        let buffer = self.buffer.read(cx);
10569        let snapshot = buffer.snapshot(cx);
10570        for selection in &mut selections {
10571            if selection.start.row != prev_edited_row {
10572                row_delta = 0;
10573            }
10574            prev_edited_row = selection.end.row;
10575
10576            row_delta =
10577                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10578        }
10579
10580        self.transact(window, cx, |this, window, cx| {
10581            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10582            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10583        });
10584    }
10585
10586    fn indent_selection(
10587        buffer: &MultiBuffer,
10588        snapshot: &MultiBufferSnapshot,
10589        selection: &mut Selection<Point>,
10590        edits: &mut Vec<(Range<Point>, String)>,
10591        delta_for_start_row: u32,
10592        cx: &App,
10593    ) -> u32 {
10594        let settings = buffer.language_settings_at(selection.start, cx);
10595        let tab_size = settings.tab_size.get();
10596        let indent_kind = if settings.hard_tabs {
10597            IndentKind::Tab
10598        } else {
10599            IndentKind::Space
10600        };
10601        let mut start_row = selection.start.row;
10602        let mut end_row = selection.end.row + 1;
10603
10604        // If a selection ends at the beginning of a line, don't indent
10605        // that last line.
10606        if selection.end.column == 0 && selection.end.row > selection.start.row {
10607            end_row -= 1;
10608        }
10609
10610        // Avoid re-indenting a row that has already been indented by a
10611        // previous selection, but still update this selection's column
10612        // to reflect that indentation.
10613        if delta_for_start_row > 0 {
10614            start_row += 1;
10615            selection.start.column += delta_for_start_row;
10616            if selection.end.row == selection.start.row {
10617                selection.end.column += delta_for_start_row;
10618            }
10619        }
10620
10621        let mut delta_for_end_row = 0;
10622        let has_multiple_rows = start_row + 1 != end_row;
10623        for row in start_row..end_row {
10624            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10625            let indent_delta = match (current_indent.kind, indent_kind) {
10626                (IndentKind::Space, IndentKind::Space) => {
10627                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10628                    IndentSize::spaces(columns_to_next_tab_stop)
10629                }
10630                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10631                (_, IndentKind::Tab) => IndentSize::tab(),
10632            };
10633
10634            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10635                0
10636            } else {
10637                selection.start.column
10638            };
10639            let row_start = Point::new(row, start);
10640            edits.push((
10641                row_start..row_start,
10642                indent_delta.chars().collect::<String>(),
10643            ));
10644
10645            // Update this selection's endpoints to reflect the indentation.
10646            if row == selection.start.row {
10647                selection.start.column += indent_delta.len;
10648            }
10649            if row == selection.end.row {
10650                selection.end.column += indent_delta.len;
10651                delta_for_end_row = indent_delta.len;
10652            }
10653        }
10654
10655        if selection.start.row == selection.end.row {
10656            delta_for_start_row + delta_for_end_row
10657        } else {
10658            delta_for_end_row
10659        }
10660    }
10661
10662    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10663        if self.read_only(cx) {
10664            return;
10665        }
10666        if self.mode.is_single_line() {
10667            cx.propagate();
10668            return;
10669        }
10670
10671        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10672        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10673        let selections = self.selections.all::<Point>(&display_map);
10674        let mut deletion_ranges = Vec::new();
10675        let mut last_outdent = None;
10676        {
10677            let buffer = self.buffer.read(cx);
10678            let snapshot = buffer.snapshot(cx);
10679            for selection in &selections {
10680                let settings = buffer.language_settings_at(selection.start, cx);
10681                let tab_size = settings.tab_size.get();
10682                let mut rows = selection.spanned_rows(false, &display_map);
10683
10684                // Avoid re-outdenting a row that has already been outdented by a
10685                // previous selection.
10686                if let Some(last_row) = last_outdent
10687                    && last_row == rows.start
10688                {
10689                    rows.start = rows.start.next_row();
10690                }
10691                let has_multiple_rows = rows.len() > 1;
10692                for row in rows.iter_rows() {
10693                    let indent_size = snapshot.indent_size_for_line(row);
10694                    if indent_size.len > 0 {
10695                        let deletion_len = match indent_size.kind {
10696                            IndentKind::Space => {
10697                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10698                                if columns_to_prev_tab_stop == 0 {
10699                                    tab_size
10700                                } else {
10701                                    columns_to_prev_tab_stop
10702                                }
10703                            }
10704                            IndentKind::Tab => 1,
10705                        };
10706                        let start = if has_multiple_rows
10707                            || deletion_len > selection.start.column
10708                            || indent_size.len < selection.start.column
10709                        {
10710                            0
10711                        } else {
10712                            selection.start.column - deletion_len
10713                        };
10714                        deletion_ranges.push(
10715                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10716                        );
10717                        last_outdent = Some(row);
10718                    }
10719                }
10720            }
10721        }
10722
10723        self.transact(window, cx, |this, window, cx| {
10724            this.buffer.update(cx, |buffer, cx| {
10725                let empty_str: Arc<str> = Arc::default();
10726                buffer.edit(
10727                    deletion_ranges
10728                        .into_iter()
10729                        .map(|range| (range, empty_str.clone())),
10730                    None,
10731                    cx,
10732                );
10733            });
10734            let selections = this
10735                .selections
10736                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10737            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10738        });
10739    }
10740
10741    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10742        if self.read_only(cx) {
10743            return;
10744        }
10745        if self.mode.is_single_line() {
10746            cx.propagate();
10747            return;
10748        }
10749
10750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10751        let selections = self
10752            .selections
10753            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10754            .into_iter()
10755            .map(|s| s.range());
10756
10757        self.transact(window, cx, |this, window, cx| {
10758            this.buffer.update(cx, |buffer, cx| {
10759                buffer.autoindent_ranges(selections, cx);
10760            });
10761            let selections = this
10762                .selections
10763                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10764            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10765        });
10766    }
10767
10768    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10769        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10770        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10771        let selections = self.selections.all::<Point>(&display_map);
10772
10773        let mut new_cursors = Vec::new();
10774        let mut edit_ranges = Vec::new();
10775        let mut selections = selections.iter().peekable();
10776        while let Some(selection) = selections.next() {
10777            let mut rows = selection.spanned_rows(false, &display_map);
10778
10779            // Accumulate contiguous regions of rows that we want to delete.
10780            while let Some(next_selection) = selections.peek() {
10781                let next_rows = next_selection.spanned_rows(false, &display_map);
10782                if next_rows.start <= rows.end {
10783                    rows.end = next_rows.end;
10784                    selections.next().unwrap();
10785                } else {
10786                    break;
10787                }
10788            }
10789
10790            let buffer = display_map.buffer_snapshot();
10791            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10792            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10793                // If there's a line after the range, delete the \n from the end of the row range
10794                (
10795                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10796                    rows.end,
10797                )
10798            } else {
10799                // If there isn't a line after the range, delete the \n from the line before the
10800                // start of the row range
10801                edit_start = edit_start.saturating_sub_usize(1);
10802                (buffer.len(), rows.start.previous_row())
10803            };
10804
10805            let text_layout_details = self.text_layout_details(window);
10806            let x = display_map.x_for_display_point(
10807                selection.head().to_display_point(&display_map),
10808                &text_layout_details,
10809            );
10810            let row = Point::new(target_row.0, 0)
10811                .to_display_point(&display_map)
10812                .row();
10813            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10814
10815            new_cursors.push((
10816                selection.id,
10817                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10818                SelectionGoal::None,
10819            ));
10820            edit_ranges.push(edit_start..edit_end);
10821        }
10822
10823        self.transact(window, cx, |this, window, cx| {
10824            let buffer = this.buffer.update(cx, |buffer, cx| {
10825                let empty_str: Arc<str> = Arc::default();
10826                buffer.edit(
10827                    edit_ranges
10828                        .into_iter()
10829                        .map(|range| (range, empty_str.clone())),
10830                    None,
10831                    cx,
10832                );
10833                buffer.snapshot(cx)
10834            });
10835            let new_selections = new_cursors
10836                .into_iter()
10837                .map(|(id, cursor, goal)| {
10838                    let cursor = cursor.to_point(&buffer);
10839                    Selection {
10840                        id,
10841                        start: cursor,
10842                        end: cursor,
10843                        reversed: false,
10844                        goal,
10845                    }
10846                })
10847                .collect();
10848
10849            this.change_selections(Default::default(), window, cx, |s| {
10850                s.select(new_selections);
10851            });
10852        });
10853    }
10854
10855    pub fn join_lines_impl(
10856        &mut self,
10857        insert_whitespace: bool,
10858        window: &mut Window,
10859        cx: &mut Context<Self>,
10860    ) {
10861        if self.read_only(cx) {
10862            return;
10863        }
10864        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10865        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10866            let start = MultiBufferRow(selection.start.row);
10867            // Treat single line selections as if they include the next line. Otherwise this action
10868            // would do nothing for single line selections individual cursors.
10869            let end = if selection.start.row == selection.end.row {
10870                MultiBufferRow(selection.start.row + 1)
10871            } else {
10872                MultiBufferRow(selection.end.row)
10873            };
10874
10875            if let Some(last_row_range) = row_ranges.last_mut()
10876                && start <= last_row_range.end
10877            {
10878                last_row_range.end = end;
10879                continue;
10880            }
10881            row_ranges.push(start..end);
10882        }
10883
10884        let snapshot = self.buffer.read(cx).snapshot(cx);
10885        let mut cursor_positions = Vec::new();
10886        for row_range in &row_ranges {
10887            let anchor = snapshot.anchor_before(Point::new(
10888                row_range.end.previous_row().0,
10889                snapshot.line_len(row_range.end.previous_row()),
10890            ));
10891            cursor_positions.push(anchor..anchor);
10892        }
10893
10894        self.transact(window, cx, |this, window, cx| {
10895            for row_range in row_ranges.into_iter().rev() {
10896                for row in row_range.iter_rows().rev() {
10897                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10898                    let next_line_row = row.next_row();
10899                    let indent = snapshot.indent_size_for_line(next_line_row);
10900                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10901
10902                    let replace =
10903                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10904                            " "
10905                        } else {
10906                            ""
10907                        };
10908
10909                    this.buffer.update(cx, |buffer, cx| {
10910                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10911                    });
10912                }
10913            }
10914
10915            this.change_selections(Default::default(), window, cx, |s| {
10916                s.select_anchor_ranges(cursor_positions)
10917            });
10918        });
10919    }
10920
10921    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10922        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10923        self.join_lines_impl(true, window, cx);
10924    }
10925
10926    pub fn sort_lines_case_sensitive(
10927        &mut self,
10928        _: &SortLinesCaseSensitive,
10929        window: &mut Window,
10930        cx: &mut Context<Self>,
10931    ) {
10932        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10933    }
10934
10935    pub fn sort_lines_by_length(
10936        &mut self,
10937        _: &SortLinesByLength,
10938        window: &mut Window,
10939        cx: &mut Context<Self>,
10940    ) {
10941        self.manipulate_immutable_lines(window, cx, |lines| {
10942            lines.sort_by_key(|&line| line.chars().count())
10943        })
10944    }
10945
10946    pub fn sort_lines_case_insensitive(
10947        &mut self,
10948        _: &SortLinesCaseInsensitive,
10949        window: &mut Window,
10950        cx: &mut Context<Self>,
10951    ) {
10952        self.manipulate_immutable_lines(window, cx, |lines| {
10953            lines.sort_by_key(|line| line.to_lowercase())
10954        })
10955    }
10956
10957    pub fn unique_lines_case_insensitive(
10958        &mut self,
10959        _: &UniqueLinesCaseInsensitive,
10960        window: &mut Window,
10961        cx: &mut Context<Self>,
10962    ) {
10963        self.manipulate_immutable_lines(window, cx, |lines| {
10964            let mut seen = HashSet::default();
10965            lines.retain(|line| seen.insert(line.to_lowercase()));
10966        })
10967    }
10968
10969    pub fn unique_lines_case_sensitive(
10970        &mut self,
10971        _: &UniqueLinesCaseSensitive,
10972        window: &mut Window,
10973        cx: &mut Context<Self>,
10974    ) {
10975        self.manipulate_immutable_lines(window, cx, |lines| {
10976            let mut seen = HashSet::default();
10977            lines.retain(|line| seen.insert(*line));
10978        })
10979    }
10980
10981    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10982        let snapshot = self.buffer.read(cx).snapshot(cx);
10983        for selection in self.selections.disjoint_anchors_arc().iter() {
10984            if snapshot
10985                .language_at(selection.start)
10986                .and_then(|lang| lang.config().wrap_characters.as_ref())
10987                .is_some()
10988            {
10989                return true;
10990            }
10991        }
10992        false
10993    }
10994
10995    fn wrap_selections_in_tag(
10996        &mut self,
10997        _: &WrapSelectionsInTag,
10998        window: &mut Window,
10999        cx: &mut Context<Self>,
11000    ) {
11001        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11002
11003        let snapshot = self.buffer.read(cx).snapshot(cx);
11004
11005        let mut edits = Vec::new();
11006        let mut boundaries = Vec::new();
11007
11008        for selection in self
11009            .selections
11010            .all_adjusted(&self.display_snapshot(cx))
11011            .iter()
11012        {
11013            let Some(wrap_config) = snapshot
11014                .language_at(selection.start)
11015                .and_then(|lang| lang.config().wrap_characters.clone())
11016            else {
11017                continue;
11018            };
11019
11020            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11021            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11022
11023            let start_before = snapshot.anchor_before(selection.start);
11024            let end_after = snapshot.anchor_after(selection.end);
11025
11026            edits.push((start_before..start_before, open_tag));
11027            edits.push((end_after..end_after, close_tag));
11028
11029            boundaries.push((
11030                start_before,
11031                end_after,
11032                wrap_config.start_prefix.len(),
11033                wrap_config.end_suffix.len(),
11034            ));
11035        }
11036
11037        if edits.is_empty() {
11038            return;
11039        }
11040
11041        self.transact(window, cx, |this, window, cx| {
11042            let buffer = this.buffer.update(cx, |buffer, cx| {
11043                buffer.edit(edits, None, cx);
11044                buffer.snapshot(cx)
11045            });
11046
11047            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11048            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11049                boundaries.into_iter()
11050            {
11051                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11052                let close_offset = end_after
11053                    .to_offset(&buffer)
11054                    .saturating_sub_usize(end_suffix_len);
11055                new_selections.push(open_offset..open_offset);
11056                new_selections.push(close_offset..close_offset);
11057            }
11058
11059            this.change_selections(Default::default(), window, cx, |s| {
11060                s.select_ranges(new_selections);
11061            });
11062
11063            this.request_autoscroll(Autoscroll::fit(), cx);
11064        });
11065    }
11066
11067    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11068        let Some(project) = self.project.clone() else {
11069            return;
11070        };
11071        self.reload(project, window, cx)
11072            .detach_and_notify_err(window, cx);
11073    }
11074
11075    pub fn restore_file(
11076        &mut self,
11077        _: &::git::RestoreFile,
11078        window: &mut Window,
11079        cx: &mut Context<Self>,
11080    ) {
11081        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11082        let mut buffer_ids = HashSet::default();
11083        let snapshot = self.buffer().read(cx).snapshot(cx);
11084        for selection in self
11085            .selections
11086            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11087        {
11088            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11089        }
11090
11091        let buffer = self.buffer().read(cx);
11092        let ranges = buffer_ids
11093            .into_iter()
11094            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11095            .collect::<Vec<_>>();
11096
11097        self.restore_hunks_in_ranges(ranges, window, cx);
11098    }
11099
11100    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11101        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11102        let selections = self
11103            .selections
11104            .all(&self.display_snapshot(cx))
11105            .into_iter()
11106            .map(|s| s.range())
11107            .collect();
11108        self.restore_hunks_in_ranges(selections, window, cx);
11109    }
11110
11111    pub fn restore_hunks_in_ranges(
11112        &mut self,
11113        ranges: Vec<Range<Point>>,
11114        window: &mut Window,
11115        cx: &mut Context<Editor>,
11116    ) {
11117        let mut revert_changes = HashMap::default();
11118        let chunk_by = self
11119            .snapshot(window, cx)
11120            .hunks_for_ranges(ranges)
11121            .into_iter()
11122            .chunk_by(|hunk| hunk.buffer_id);
11123        for (buffer_id, hunks) in &chunk_by {
11124            let hunks = hunks.collect::<Vec<_>>();
11125            for hunk in &hunks {
11126                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11127            }
11128            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11129        }
11130        drop(chunk_by);
11131        if !revert_changes.is_empty() {
11132            self.transact(window, cx, |editor, window, cx| {
11133                editor.restore(revert_changes, window, cx);
11134            });
11135        }
11136    }
11137
11138    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11139        if let Some(status) = self
11140            .addons
11141            .iter()
11142            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11143        {
11144            return Some(status);
11145        }
11146        self.project
11147            .as_ref()?
11148            .read(cx)
11149            .status_for_buffer_id(buffer_id, cx)
11150    }
11151
11152    pub fn open_active_item_in_terminal(
11153        &mut self,
11154        _: &OpenInTerminal,
11155        window: &mut Window,
11156        cx: &mut Context<Self>,
11157    ) {
11158        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11159            let project_path = buffer.read(cx).project_path(cx)?;
11160            let project = self.project()?.read(cx);
11161            let entry = project.entry_for_path(&project_path, cx)?;
11162            let parent = match &entry.canonical_path {
11163                Some(canonical_path) => canonical_path.to_path_buf(),
11164                None => project.absolute_path(&project_path, cx)?,
11165            }
11166            .parent()?
11167            .to_path_buf();
11168            Some(parent)
11169        }) {
11170            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11171        }
11172    }
11173
11174    fn set_breakpoint_context_menu(
11175        &mut self,
11176        display_row: DisplayRow,
11177        position: Option<Anchor>,
11178        clicked_point: gpui::Point<Pixels>,
11179        window: &mut Window,
11180        cx: &mut Context<Self>,
11181    ) {
11182        let source = self
11183            .buffer
11184            .read(cx)
11185            .snapshot(cx)
11186            .anchor_before(Point::new(display_row.0, 0u32));
11187
11188        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11189
11190        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11191            self,
11192            source,
11193            clicked_point,
11194            context_menu,
11195            window,
11196            cx,
11197        );
11198    }
11199
11200    fn add_edit_breakpoint_block(
11201        &mut self,
11202        anchor: Anchor,
11203        breakpoint: &Breakpoint,
11204        edit_action: BreakpointPromptEditAction,
11205        window: &mut Window,
11206        cx: &mut Context<Self>,
11207    ) {
11208        let weak_editor = cx.weak_entity();
11209        let bp_prompt = cx.new(|cx| {
11210            BreakpointPromptEditor::new(
11211                weak_editor,
11212                anchor,
11213                breakpoint.clone(),
11214                edit_action,
11215                window,
11216                cx,
11217            )
11218        });
11219
11220        let height = bp_prompt.update(cx, |this, cx| {
11221            this.prompt
11222                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11223        });
11224        let cloned_prompt = bp_prompt.clone();
11225        let blocks = vec![BlockProperties {
11226            style: BlockStyle::Sticky,
11227            placement: BlockPlacement::Above(anchor),
11228            height: Some(height),
11229            render: Arc::new(move |cx| {
11230                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11231                cloned_prompt.clone().into_any_element()
11232            }),
11233            priority: 0,
11234        }];
11235
11236        let focus_handle = bp_prompt.focus_handle(cx);
11237        window.focus(&focus_handle, cx);
11238
11239        let block_ids = self.insert_blocks(blocks, None, cx);
11240        bp_prompt.update(cx, |prompt, _| {
11241            prompt.add_block_ids(block_ids);
11242        });
11243    }
11244
11245    pub(crate) fn breakpoint_at_row(
11246        &self,
11247        row: u32,
11248        window: &mut Window,
11249        cx: &mut Context<Self>,
11250    ) -> Option<(Anchor, Breakpoint)> {
11251        let snapshot = self.snapshot(window, cx);
11252        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11253
11254        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11255    }
11256
11257    pub(crate) fn breakpoint_at_anchor(
11258        &self,
11259        breakpoint_position: Anchor,
11260        snapshot: &EditorSnapshot,
11261        cx: &mut Context<Self>,
11262    ) -> Option<(Anchor, Breakpoint)> {
11263        let buffer = self
11264            .buffer
11265            .read(cx)
11266            .buffer_for_anchor(breakpoint_position, cx)?;
11267
11268        let enclosing_excerpt = breakpoint_position.excerpt_id;
11269        let buffer_snapshot = buffer.read(cx).snapshot();
11270
11271        let row = buffer_snapshot
11272            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11273            .row;
11274
11275        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11276        let anchor_end = snapshot
11277            .buffer_snapshot()
11278            .anchor_after(Point::new(row, line_len));
11279
11280        self.breakpoint_store
11281            .as_ref()?
11282            .read_with(cx, |breakpoint_store, cx| {
11283                breakpoint_store
11284                    .breakpoints(
11285                        &buffer,
11286                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11287                        &buffer_snapshot,
11288                        cx,
11289                    )
11290                    .next()
11291                    .and_then(|(bp, _)| {
11292                        let breakpoint_row = buffer_snapshot
11293                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11294                            .row;
11295
11296                        if breakpoint_row == row {
11297                            snapshot
11298                                .buffer_snapshot()
11299                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11300                                .map(|position| (position, bp.bp.clone()))
11301                        } else {
11302                            None
11303                        }
11304                    })
11305            })
11306    }
11307
11308    pub fn edit_log_breakpoint(
11309        &mut self,
11310        _: &EditLogBreakpoint,
11311        window: &mut Window,
11312        cx: &mut Context<Self>,
11313    ) {
11314        if self.breakpoint_store.is_none() {
11315            return;
11316        }
11317
11318        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11319            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11320                message: None,
11321                state: BreakpointState::Enabled,
11322                condition: None,
11323                hit_condition: None,
11324            });
11325
11326            self.add_edit_breakpoint_block(
11327                anchor,
11328                &breakpoint,
11329                BreakpointPromptEditAction::Log,
11330                window,
11331                cx,
11332            );
11333        }
11334    }
11335
11336    fn breakpoints_at_cursors(
11337        &self,
11338        window: &mut Window,
11339        cx: &mut Context<Self>,
11340    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11341        let snapshot = self.snapshot(window, cx);
11342        let cursors = self
11343            .selections
11344            .disjoint_anchors_arc()
11345            .iter()
11346            .map(|selection| {
11347                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11348
11349                let breakpoint_position = self
11350                    .breakpoint_at_row(cursor_position.row, window, cx)
11351                    .map(|bp| bp.0)
11352                    .unwrap_or_else(|| {
11353                        snapshot
11354                            .display_snapshot
11355                            .buffer_snapshot()
11356                            .anchor_after(Point::new(cursor_position.row, 0))
11357                    });
11358
11359                let breakpoint = self
11360                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11361                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11362
11363                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11364            })
11365            // 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.
11366            .collect::<HashMap<Anchor, _>>();
11367
11368        cursors.into_iter().collect()
11369    }
11370
11371    pub fn enable_breakpoint(
11372        &mut self,
11373        _: &crate::actions::EnableBreakpoint,
11374        window: &mut Window,
11375        cx: &mut Context<Self>,
11376    ) {
11377        if self.breakpoint_store.is_none() {
11378            return;
11379        }
11380
11381        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11382            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11383                continue;
11384            };
11385            self.edit_breakpoint_at_anchor(
11386                anchor,
11387                breakpoint,
11388                BreakpointEditAction::InvertState,
11389                cx,
11390            );
11391        }
11392    }
11393
11394    pub fn disable_breakpoint(
11395        &mut self,
11396        _: &crate::actions::DisableBreakpoint,
11397        window: &mut Window,
11398        cx: &mut Context<Self>,
11399    ) {
11400        if self.breakpoint_store.is_none() {
11401            return;
11402        }
11403
11404        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11405            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11406                continue;
11407            };
11408            self.edit_breakpoint_at_anchor(
11409                anchor,
11410                breakpoint,
11411                BreakpointEditAction::InvertState,
11412                cx,
11413            );
11414        }
11415    }
11416
11417    pub fn toggle_breakpoint(
11418        &mut self,
11419        _: &crate::actions::ToggleBreakpoint,
11420        window: &mut Window,
11421        cx: &mut Context<Self>,
11422    ) {
11423        if self.breakpoint_store.is_none() {
11424            return;
11425        }
11426
11427        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11428            if let Some(breakpoint) = breakpoint {
11429                self.edit_breakpoint_at_anchor(
11430                    anchor,
11431                    breakpoint,
11432                    BreakpointEditAction::Toggle,
11433                    cx,
11434                );
11435            } else {
11436                self.edit_breakpoint_at_anchor(
11437                    anchor,
11438                    Breakpoint::new_standard(),
11439                    BreakpointEditAction::Toggle,
11440                    cx,
11441                );
11442            }
11443        }
11444    }
11445
11446    pub fn edit_breakpoint_at_anchor(
11447        &mut self,
11448        breakpoint_position: Anchor,
11449        breakpoint: Breakpoint,
11450        edit_action: BreakpointEditAction,
11451        cx: &mut Context<Self>,
11452    ) {
11453        let Some(breakpoint_store) = &self.breakpoint_store else {
11454            return;
11455        };
11456
11457        let Some(buffer) = self
11458            .buffer
11459            .read(cx)
11460            .buffer_for_anchor(breakpoint_position, cx)
11461        else {
11462            return;
11463        };
11464
11465        breakpoint_store.update(cx, |breakpoint_store, cx| {
11466            breakpoint_store.toggle_breakpoint(
11467                buffer,
11468                BreakpointWithPosition {
11469                    position: breakpoint_position.text_anchor,
11470                    bp: breakpoint,
11471                },
11472                edit_action,
11473                cx,
11474            );
11475        });
11476
11477        cx.notify();
11478    }
11479
11480    #[cfg(any(test, feature = "test-support"))]
11481    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11482        self.breakpoint_store.clone()
11483    }
11484
11485    pub fn prepare_restore_change(
11486        &self,
11487        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11488        hunk: &MultiBufferDiffHunk,
11489        cx: &mut App,
11490    ) -> Option<()> {
11491        if hunk.is_created_file() {
11492            return None;
11493        }
11494        let buffer = self.buffer.read(cx);
11495        let diff = buffer.diff_for(hunk.buffer_id)?;
11496        let buffer = buffer.buffer(hunk.buffer_id)?;
11497        let buffer = buffer.read(cx);
11498        let original_text = diff
11499            .read(cx)
11500            .base_text()
11501            .as_rope()
11502            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11503        let buffer_snapshot = buffer.snapshot();
11504        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11505        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11506            probe
11507                .0
11508                .start
11509                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11510                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11511        }) {
11512            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11513            Some(())
11514        } else {
11515            None
11516        }
11517    }
11518
11519    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11520        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11521    }
11522
11523    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11524        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11525    }
11526
11527    pub fn rotate_selections_forward(
11528        &mut self,
11529        _: &RotateSelectionsForward,
11530        window: &mut Window,
11531        cx: &mut Context<Self>,
11532    ) {
11533        self.rotate_selections(window, cx, false)
11534    }
11535
11536    pub fn rotate_selections_backward(
11537        &mut self,
11538        _: &RotateSelectionsBackward,
11539        window: &mut Window,
11540        cx: &mut Context<Self>,
11541    ) {
11542        self.rotate_selections(window, cx, true)
11543    }
11544
11545    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11546        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11547        let display_snapshot = self.display_snapshot(cx);
11548        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11549
11550        if selections.len() < 2 {
11551            return;
11552        }
11553
11554        let (edits, new_selections) = {
11555            let buffer = self.buffer.read(cx).read(cx);
11556            let has_selections = selections.iter().any(|s| !s.is_empty());
11557            if has_selections {
11558                let mut selected_texts: Vec<String> = selections
11559                    .iter()
11560                    .map(|selection| {
11561                        buffer
11562                            .text_for_range(selection.start..selection.end)
11563                            .collect()
11564                    })
11565                    .collect();
11566
11567                if reverse {
11568                    selected_texts.rotate_left(1);
11569                } else {
11570                    selected_texts.rotate_right(1);
11571                }
11572
11573                let mut offset_delta: i64 = 0;
11574                let mut new_selections = Vec::new();
11575                let edits: Vec<_> = selections
11576                    .iter()
11577                    .zip(selected_texts.iter())
11578                    .map(|(selection, new_text)| {
11579                        let old_len = (selection.end.0 - selection.start.0) as i64;
11580                        let new_len = new_text.len() as i64;
11581                        let adjusted_start =
11582                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11583                        let adjusted_end =
11584                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11585
11586                        new_selections.push(Selection {
11587                            id: selection.id,
11588                            start: adjusted_start,
11589                            end: adjusted_end,
11590                            reversed: selection.reversed,
11591                            goal: selection.goal,
11592                        });
11593
11594                        offset_delta += new_len - old_len;
11595                        (selection.start..selection.end, new_text.clone())
11596                    })
11597                    .collect();
11598                (edits, new_selections)
11599            } else {
11600                let mut all_rows: Vec<u32> = selections
11601                    .iter()
11602                    .map(|selection| buffer.offset_to_point(selection.start).row)
11603                    .collect();
11604                all_rows.sort_unstable();
11605                all_rows.dedup();
11606
11607                if all_rows.len() < 2 {
11608                    return;
11609                }
11610
11611                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11612                    .iter()
11613                    .map(|&row| {
11614                        let start = Point::new(row, 0);
11615                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11616                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11617                    })
11618                    .collect();
11619
11620                let mut line_texts: Vec<String> = line_ranges
11621                    .iter()
11622                    .map(|range| buffer.text_for_range(range.clone()).collect())
11623                    .collect();
11624
11625                if reverse {
11626                    line_texts.rotate_left(1);
11627                } else {
11628                    line_texts.rotate_right(1);
11629                }
11630
11631                let edits = line_ranges
11632                    .iter()
11633                    .zip(line_texts.iter())
11634                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11635                    .collect();
11636
11637                let num_rows = all_rows.len();
11638                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11639                    .iter()
11640                    .enumerate()
11641                    .map(|(i, &row)| (row, i))
11642                    .collect();
11643
11644                // Compute new line start offsets after rotation (handles CRLF)
11645                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11646                let first_line_start = line_ranges[0].start.0;
11647                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11648                for text in line_texts.iter().take(num_rows - 1) {
11649                    let prev_start = *new_line_starts.last().unwrap();
11650                    new_line_starts.push(prev_start + text.len() + newline_len);
11651                }
11652
11653                let new_selections = selections
11654                    .iter()
11655                    .map(|selection| {
11656                        let point = buffer.offset_to_point(selection.start);
11657                        let old_index = row_to_index[&point.row];
11658                        let new_index = if reverse {
11659                            (old_index + num_rows - 1) % num_rows
11660                        } else {
11661                            (old_index + 1) % num_rows
11662                        };
11663                        let new_offset =
11664                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11665                        Selection {
11666                            id: selection.id,
11667                            start: new_offset,
11668                            end: new_offset,
11669                            reversed: selection.reversed,
11670                            goal: selection.goal,
11671                        }
11672                    })
11673                    .collect();
11674
11675                (edits, new_selections)
11676            }
11677        };
11678
11679        self.transact(window, cx, |this, window, cx| {
11680            this.buffer.update(cx, |buffer, cx| {
11681                buffer.edit(edits, None, cx);
11682            });
11683            this.change_selections(Default::default(), window, cx, |s| {
11684                s.select(new_selections);
11685            });
11686        });
11687    }
11688
11689    fn manipulate_lines<M>(
11690        &mut self,
11691        window: &mut Window,
11692        cx: &mut Context<Self>,
11693        mut manipulate: M,
11694    ) where
11695        M: FnMut(&str) -> LineManipulationResult,
11696    {
11697        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11698
11699        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11700        let buffer = self.buffer.read(cx).snapshot(cx);
11701
11702        let mut edits = Vec::new();
11703
11704        let selections = self.selections.all::<Point>(&display_map);
11705        let mut selections = selections.iter().peekable();
11706        let mut contiguous_row_selections = Vec::new();
11707        let mut new_selections = Vec::new();
11708        let mut added_lines = 0;
11709        let mut removed_lines = 0;
11710
11711        while let Some(selection) = selections.next() {
11712            let (start_row, end_row) = consume_contiguous_rows(
11713                &mut contiguous_row_selections,
11714                selection,
11715                &display_map,
11716                &mut selections,
11717            );
11718
11719            let start_point = Point::new(start_row.0, 0);
11720            let end_point = Point::new(
11721                end_row.previous_row().0,
11722                buffer.line_len(end_row.previous_row()),
11723            );
11724            let text = buffer
11725                .text_for_range(start_point..end_point)
11726                .collect::<String>();
11727
11728            let LineManipulationResult {
11729                new_text,
11730                line_count_before,
11731                line_count_after,
11732            } = manipulate(&text);
11733
11734            edits.push((start_point..end_point, new_text));
11735
11736            // Selections must change based on added and removed line count
11737            let start_row =
11738                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11739            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11740            new_selections.push(Selection {
11741                id: selection.id,
11742                start: start_row,
11743                end: end_row,
11744                goal: SelectionGoal::None,
11745                reversed: selection.reversed,
11746            });
11747
11748            if line_count_after > line_count_before {
11749                added_lines += line_count_after - line_count_before;
11750            } else if line_count_before > line_count_after {
11751                removed_lines += line_count_before - line_count_after;
11752            }
11753        }
11754
11755        self.transact(window, cx, |this, window, cx| {
11756            let buffer = this.buffer.update(cx, |buffer, cx| {
11757                buffer.edit(edits, None, cx);
11758                buffer.snapshot(cx)
11759            });
11760
11761            // Recalculate offsets on newly edited buffer
11762            let new_selections = new_selections
11763                .iter()
11764                .map(|s| {
11765                    let start_point = Point::new(s.start.0, 0);
11766                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11767                    Selection {
11768                        id: s.id,
11769                        start: buffer.point_to_offset(start_point),
11770                        end: buffer.point_to_offset(end_point),
11771                        goal: s.goal,
11772                        reversed: s.reversed,
11773                    }
11774                })
11775                .collect();
11776
11777            this.change_selections(Default::default(), window, cx, |s| {
11778                s.select(new_selections);
11779            });
11780
11781            this.request_autoscroll(Autoscroll::fit(), cx);
11782        });
11783    }
11784
11785    fn manipulate_immutable_lines<Fn>(
11786        &mut self,
11787        window: &mut Window,
11788        cx: &mut Context<Self>,
11789        mut callback: Fn,
11790    ) where
11791        Fn: FnMut(&mut Vec<&str>),
11792    {
11793        self.manipulate_lines(window, cx, |text| {
11794            let mut lines: Vec<&str> = text.split('\n').collect();
11795            let line_count_before = lines.len();
11796
11797            callback(&mut lines);
11798
11799            LineManipulationResult {
11800                new_text: lines.join("\n"),
11801                line_count_before,
11802                line_count_after: lines.len(),
11803            }
11804        });
11805    }
11806
11807    fn manipulate_mutable_lines<Fn>(
11808        &mut self,
11809        window: &mut Window,
11810        cx: &mut Context<Self>,
11811        mut callback: Fn,
11812    ) where
11813        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11814    {
11815        self.manipulate_lines(window, cx, |text| {
11816            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11817            let line_count_before = lines.len();
11818
11819            callback(&mut lines);
11820
11821            LineManipulationResult {
11822                new_text: lines.join("\n"),
11823                line_count_before,
11824                line_count_after: lines.len(),
11825            }
11826        });
11827    }
11828
11829    pub fn convert_indentation_to_spaces(
11830        &mut self,
11831        _: &ConvertIndentationToSpaces,
11832        window: &mut Window,
11833        cx: &mut Context<Self>,
11834    ) {
11835        let settings = self.buffer.read(cx).language_settings(cx);
11836        let tab_size = settings.tab_size.get() as usize;
11837
11838        self.manipulate_mutable_lines(window, cx, |lines| {
11839            // Allocates a reasonably sized scratch buffer once for the whole loop
11840            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11841            // Avoids recomputing spaces that could be inserted many times
11842            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11843                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11844                .collect();
11845
11846            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11847                let mut chars = line.as_ref().chars();
11848                let mut col = 0;
11849                let mut changed = false;
11850
11851                for ch in chars.by_ref() {
11852                    match ch {
11853                        ' ' => {
11854                            reindented_line.push(' ');
11855                            col += 1;
11856                        }
11857                        '\t' => {
11858                            // \t are converted to spaces depending on the current column
11859                            let spaces_len = tab_size - (col % tab_size);
11860                            reindented_line.extend(&space_cache[spaces_len - 1]);
11861                            col += spaces_len;
11862                            changed = true;
11863                        }
11864                        _ => {
11865                            // If we dont append before break, the character is consumed
11866                            reindented_line.push(ch);
11867                            break;
11868                        }
11869                    }
11870                }
11871
11872                if !changed {
11873                    reindented_line.clear();
11874                    continue;
11875                }
11876                // Append the rest of the line and replace old reference with new one
11877                reindented_line.extend(chars);
11878                *line = Cow::Owned(reindented_line.clone());
11879                reindented_line.clear();
11880            }
11881        });
11882    }
11883
11884    pub fn convert_indentation_to_tabs(
11885        &mut self,
11886        _: &ConvertIndentationToTabs,
11887        window: &mut Window,
11888        cx: &mut Context<Self>,
11889    ) {
11890        let settings = self.buffer.read(cx).language_settings(cx);
11891        let tab_size = settings.tab_size.get() as usize;
11892
11893        self.manipulate_mutable_lines(window, cx, |lines| {
11894            // Allocates a reasonably sized buffer once for the whole loop
11895            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11896            // Avoids recomputing spaces that could be inserted many times
11897            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11898                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11899                .collect();
11900
11901            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11902                let mut chars = line.chars();
11903                let mut spaces_count = 0;
11904                let mut first_non_indent_char = None;
11905                let mut changed = false;
11906
11907                for ch in chars.by_ref() {
11908                    match ch {
11909                        ' ' => {
11910                            // Keep track of spaces. Append \t when we reach tab_size
11911                            spaces_count += 1;
11912                            changed = true;
11913                            if spaces_count == tab_size {
11914                                reindented_line.push('\t');
11915                                spaces_count = 0;
11916                            }
11917                        }
11918                        '\t' => {
11919                            reindented_line.push('\t');
11920                            spaces_count = 0;
11921                        }
11922                        _ => {
11923                            // Dont append it yet, we might have remaining spaces
11924                            first_non_indent_char = Some(ch);
11925                            break;
11926                        }
11927                    }
11928                }
11929
11930                if !changed {
11931                    reindented_line.clear();
11932                    continue;
11933                }
11934                // Remaining spaces that didn't make a full tab stop
11935                if spaces_count > 0 {
11936                    reindented_line.extend(&space_cache[spaces_count - 1]);
11937                }
11938                // If we consume an extra character that was not indentation, add it back
11939                if let Some(extra_char) = first_non_indent_char {
11940                    reindented_line.push(extra_char);
11941                }
11942                // Append the rest of the line and replace old reference with new one
11943                reindented_line.extend(chars);
11944                *line = Cow::Owned(reindented_line.clone());
11945                reindented_line.clear();
11946            }
11947        });
11948    }
11949
11950    pub fn convert_to_upper_case(
11951        &mut self,
11952        _: &ConvertToUpperCase,
11953        window: &mut Window,
11954        cx: &mut Context<Self>,
11955    ) {
11956        self.manipulate_text(window, cx, |text| text.to_uppercase())
11957    }
11958
11959    pub fn convert_to_lower_case(
11960        &mut self,
11961        _: &ConvertToLowerCase,
11962        window: &mut Window,
11963        cx: &mut Context<Self>,
11964    ) {
11965        self.manipulate_text(window, cx, |text| text.to_lowercase())
11966    }
11967
11968    pub fn convert_to_title_case(
11969        &mut self,
11970        _: &ConvertToTitleCase,
11971        window: &mut Window,
11972        cx: &mut Context<Self>,
11973    ) {
11974        self.manipulate_text(window, cx, |text| {
11975            text.split('\n')
11976                .map(|line| line.to_case(Case::Title))
11977                .join("\n")
11978        })
11979    }
11980
11981    pub fn convert_to_snake_case(
11982        &mut self,
11983        _: &ConvertToSnakeCase,
11984        window: &mut Window,
11985        cx: &mut Context<Self>,
11986    ) {
11987        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11988    }
11989
11990    pub fn convert_to_kebab_case(
11991        &mut self,
11992        _: &ConvertToKebabCase,
11993        window: &mut Window,
11994        cx: &mut Context<Self>,
11995    ) {
11996        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11997    }
11998
11999    pub fn convert_to_upper_camel_case(
12000        &mut self,
12001        _: &ConvertToUpperCamelCase,
12002        window: &mut Window,
12003        cx: &mut Context<Self>,
12004    ) {
12005        self.manipulate_text(window, cx, |text| {
12006            text.split('\n')
12007                .map(|line| line.to_case(Case::UpperCamel))
12008                .join("\n")
12009        })
12010    }
12011
12012    pub fn convert_to_lower_camel_case(
12013        &mut self,
12014        _: &ConvertToLowerCamelCase,
12015        window: &mut Window,
12016        cx: &mut Context<Self>,
12017    ) {
12018        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12019    }
12020
12021    pub fn convert_to_opposite_case(
12022        &mut self,
12023        _: &ConvertToOppositeCase,
12024        window: &mut Window,
12025        cx: &mut Context<Self>,
12026    ) {
12027        self.manipulate_text(window, cx, |text| {
12028            text.chars()
12029                .fold(String::with_capacity(text.len()), |mut t, c| {
12030                    if c.is_uppercase() {
12031                        t.extend(c.to_lowercase());
12032                    } else {
12033                        t.extend(c.to_uppercase());
12034                    }
12035                    t
12036                })
12037        })
12038    }
12039
12040    pub fn convert_to_sentence_case(
12041        &mut self,
12042        _: &ConvertToSentenceCase,
12043        window: &mut Window,
12044        cx: &mut Context<Self>,
12045    ) {
12046        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12047    }
12048
12049    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12050        self.manipulate_text(window, cx, |text| {
12051            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12052            if has_upper_case_characters {
12053                text.to_lowercase()
12054            } else {
12055                text.to_uppercase()
12056            }
12057        })
12058    }
12059
12060    pub fn convert_to_rot13(
12061        &mut self,
12062        _: &ConvertToRot13,
12063        window: &mut Window,
12064        cx: &mut Context<Self>,
12065    ) {
12066        self.manipulate_text(window, cx, |text| {
12067            text.chars()
12068                .map(|c| match c {
12069                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12070                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12071                    _ => c,
12072                })
12073                .collect()
12074        })
12075    }
12076
12077    pub fn convert_to_rot47(
12078        &mut self,
12079        _: &ConvertToRot47,
12080        window: &mut Window,
12081        cx: &mut Context<Self>,
12082    ) {
12083        self.manipulate_text(window, cx, |text| {
12084            text.chars()
12085                .map(|c| {
12086                    let code_point = c as u32;
12087                    if code_point >= 33 && code_point <= 126 {
12088                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12089                    }
12090                    c
12091                })
12092                .collect()
12093        })
12094    }
12095
12096    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12097    where
12098        Fn: FnMut(&str) -> String,
12099    {
12100        let buffer = self.buffer.read(cx).snapshot(cx);
12101
12102        let mut new_selections = Vec::new();
12103        let mut edits = Vec::new();
12104        let mut selection_adjustment = 0isize;
12105
12106        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12107            let selection_is_empty = selection.is_empty();
12108
12109            let (start, end) = if selection_is_empty {
12110                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12111                (word_range.start, word_range.end)
12112            } else {
12113                (
12114                    buffer.point_to_offset(selection.start),
12115                    buffer.point_to_offset(selection.end),
12116                )
12117            };
12118
12119            let text = buffer.text_for_range(start..end).collect::<String>();
12120            let old_length = text.len() as isize;
12121            let text = callback(&text);
12122
12123            new_selections.push(Selection {
12124                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12125                end: MultiBufferOffset(
12126                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12127                ),
12128                goal: SelectionGoal::None,
12129                id: selection.id,
12130                reversed: selection.reversed,
12131            });
12132
12133            selection_adjustment += old_length - text.len() as isize;
12134
12135            edits.push((start..end, text));
12136        }
12137
12138        self.transact(window, cx, |this, window, cx| {
12139            this.buffer.update(cx, |buffer, cx| {
12140                buffer.edit(edits, None, cx);
12141            });
12142
12143            this.change_selections(Default::default(), window, cx, |s| {
12144                s.select(new_selections);
12145            });
12146
12147            this.request_autoscroll(Autoscroll::fit(), cx);
12148        });
12149    }
12150
12151    pub fn move_selection_on_drop(
12152        &mut self,
12153        selection: &Selection<Anchor>,
12154        target: DisplayPoint,
12155        is_cut: bool,
12156        window: &mut Window,
12157        cx: &mut Context<Self>,
12158    ) {
12159        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12160        let buffer = display_map.buffer_snapshot();
12161        let mut edits = Vec::new();
12162        let insert_point = display_map
12163            .clip_point(target, Bias::Left)
12164            .to_point(&display_map);
12165        let text = buffer
12166            .text_for_range(selection.start..selection.end)
12167            .collect::<String>();
12168        if is_cut {
12169            edits.push(((selection.start..selection.end), String::new()));
12170        }
12171        let insert_anchor = buffer.anchor_before(insert_point);
12172        edits.push(((insert_anchor..insert_anchor), text));
12173        let last_edit_start = insert_anchor.bias_left(buffer);
12174        let last_edit_end = insert_anchor.bias_right(buffer);
12175        self.transact(window, cx, |this, window, cx| {
12176            this.buffer.update(cx, |buffer, cx| {
12177                buffer.edit(edits, None, cx);
12178            });
12179            this.change_selections(Default::default(), window, cx, |s| {
12180                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12181            });
12182        });
12183    }
12184
12185    pub fn clear_selection_drag_state(&mut self) {
12186        self.selection_drag_state = SelectionDragState::None;
12187    }
12188
12189    pub fn duplicate(
12190        &mut self,
12191        upwards: bool,
12192        whole_lines: bool,
12193        window: &mut Window,
12194        cx: &mut Context<Self>,
12195    ) {
12196        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12197
12198        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12199        let buffer = display_map.buffer_snapshot();
12200        let selections = self.selections.all::<Point>(&display_map);
12201
12202        let mut edits = Vec::new();
12203        let mut selections_iter = selections.iter().peekable();
12204        while let Some(selection) = selections_iter.next() {
12205            let mut rows = selection.spanned_rows(false, &display_map);
12206            // duplicate line-wise
12207            if whole_lines || selection.start == selection.end {
12208                // Avoid duplicating the same lines twice.
12209                while let Some(next_selection) = selections_iter.peek() {
12210                    let next_rows = next_selection.spanned_rows(false, &display_map);
12211                    if next_rows.start < rows.end {
12212                        rows.end = next_rows.end;
12213                        selections_iter.next().unwrap();
12214                    } else {
12215                        break;
12216                    }
12217                }
12218
12219                // Copy the text from the selected row region and splice it either at the start
12220                // or end of the region.
12221                let start = Point::new(rows.start.0, 0);
12222                let end = Point::new(
12223                    rows.end.previous_row().0,
12224                    buffer.line_len(rows.end.previous_row()),
12225                );
12226
12227                let mut text = buffer.text_for_range(start..end).collect::<String>();
12228
12229                let insert_location = if upwards {
12230                    // When duplicating upward, we need to insert before the current line.
12231                    // If we're on the last line and it doesn't end with a newline,
12232                    // we need to add a newline before the duplicated content.
12233                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12234                        && buffer.max_point().column > 0
12235                        && !text.ends_with('\n');
12236
12237                    if needs_leading_newline {
12238                        text.insert(0, '\n');
12239                        end
12240                    } else {
12241                        text.push('\n');
12242                        Point::new(rows.start.0, 0)
12243                    }
12244                } else {
12245                    text.push('\n');
12246                    start
12247                };
12248                edits.push((insert_location..insert_location, text));
12249            } else {
12250                // duplicate character-wise
12251                let start = selection.start;
12252                let end = selection.end;
12253                let text = buffer.text_for_range(start..end).collect::<String>();
12254                edits.push((selection.end..selection.end, text));
12255            }
12256        }
12257
12258        self.transact(window, cx, |this, window, cx| {
12259            this.buffer.update(cx, |buffer, cx| {
12260                buffer.edit(edits, None, cx);
12261            });
12262
12263            // When duplicating upward with whole lines, move the cursor to the duplicated line
12264            if upwards && whole_lines {
12265                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12266
12267                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12268                    let mut new_ranges = Vec::new();
12269                    let selections = s.all::<Point>(&display_map);
12270                    let mut selections_iter = selections.iter().peekable();
12271
12272                    while let Some(first_selection) = selections_iter.next() {
12273                        // Group contiguous selections together to find the total row span
12274                        let mut group_selections = vec![first_selection];
12275                        let mut rows = first_selection.spanned_rows(false, &display_map);
12276
12277                        while let Some(next_selection) = selections_iter.peek() {
12278                            let next_rows = next_selection.spanned_rows(false, &display_map);
12279                            if next_rows.start < rows.end {
12280                                rows.end = next_rows.end;
12281                                group_selections.push(selections_iter.next().unwrap());
12282                            } else {
12283                                break;
12284                            }
12285                        }
12286
12287                        let row_count = rows.end.0 - rows.start.0;
12288
12289                        // Move all selections in this group up by the total number of duplicated rows
12290                        for selection in group_selections {
12291                            let new_start = Point::new(
12292                                selection.start.row.saturating_sub(row_count),
12293                                selection.start.column,
12294                            );
12295
12296                            let new_end = Point::new(
12297                                selection.end.row.saturating_sub(row_count),
12298                                selection.end.column,
12299                            );
12300
12301                            new_ranges.push(new_start..new_end);
12302                        }
12303                    }
12304
12305                    s.select_ranges(new_ranges);
12306                });
12307            }
12308
12309            this.request_autoscroll(Autoscroll::fit(), cx);
12310        });
12311    }
12312
12313    pub fn duplicate_line_up(
12314        &mut self,
12315        _: &DuplicateLineUp,
12316        window: &mut Window,
12317        cx: &mut Context<Self>,
12318    ) {
12319        self.duplicate(true, true, window, cx);
12320    }
12321
12322    pub fn duplicate_line_down(
12323        &mut self,
12324        _: &DuplicateLineDown,
12325        window: &mut Window,
12326        cx: &mut Context<Self>,
12327    ) {
12328        self.duplicate(false, true, window, cx);
12329    }
12330
12331    pub fn duplicate_selection(
12332        &mut self,
12333        _: &DuplicateSelection,
12334        window: &mut Window,
12335        cx: &mut Context<Self>,
12336    ) {
12337        self.duplicate(false, false, window, cx);
12338    }
12339
12340    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12341        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12342        if self.mode.is_single_line() {
12343            cx.propagate();
12344            return;
12345        }
12346
12347        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12348        let buffer = self.buffer.read(cx).snapshot(cx);
12349
12350        let mut edits = Vec::new();
12351        let mut unfold_ranges = Vec::new();
12352        let mut refold_creases = Vec::new();
12353
12354        let selections = self.selections.all::<Point>(&display_map);
12355        let mut selections = selections.iter().peekable();
12356        let mut contiguous_row_selections = Vec::new();
12357        let mut new_selections = Vec::new();
12358
12359        while let Some(selection) = selections.next() {
12360            // Find all the selections that span a contiguous row range
12361            let (start_row, end_row) = consume_contiguous_rows(
12362                &mut contiguous_row_selections,
12363                selection,
12364                &display_map,
12365                &mut selections,
12366            );
12367
12368            // Move the text spanned by the row range to be before the line preceding the row range
12369            if start_row.0 > 0 {
12370                let range_to_move = Point::new(
12371                    start_row.previous_row().0,
12372                    buffer.line_len(start_row.previous_row()),
12373                )
12374                    ..Point::new(
12375                        end_row.previous_row().0,
12376                        buffer.line_len(end_row.previous_row()),
12377                    );
12378                let insertion_point = display_map
12379                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12380                    .0;
12381
12382                // Don't move lines across excerpts
12383                if buffer
12384                    .excerpt_containing(insertion_point..range_to_move.end)
12385                    .is_some()
12386                {
12387                    let text = buffer
12388                        .text_for_range(range_to_move.clone())
12389                        .flat_map(|s| s.chars())
12390                        .skip(1)
12391                        .chain(['\n'])
12392                        .collect::<String>();
12393
12394                    edits.push((
12395                        buffer.anchor_after(range_to_move.start)
12396                            ..buffer.anchor_before(range_to_move.end),
12397                        String::new(),
12398                    ));
12399                    let insertion_anchor = buffer.anchor_after(insertion_point);
12400                    edits.push((insertion_anchor..insertion_anchor, text));
12401
12402                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12403
12404                    // Move selections up
12405                    new_selections.extend(contiguous_row_selections.drain(..).map(
12406                        |mut selection| {
12407                            selection.start.row -= row_delta;
12408                            selection.end.row -= row_delta;
12409                            selection
12410                        },
12411                    ));
12412
12413                    // Move folds up
12414                    unfold_ranges.push(range_to_move.clone());
12415                    for fold in display_map.folds_in_range(
12416                        buffer.anchor_before(range_to_move.start)
12417                            ..buffer.anchor_after(range_to_move.end),
12418                    ) {
12419                        let mut start = fold.range.start.to_point(&buffer);
12420                        let mut end = fold.range.end.to_point(&buffer);
12421                        start.row -= row_delta;
12422                        end.row -= row_delta;
12423                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12424                    }
12425                }
12426            }
12427
12428            // If we didn't move line(s), preserve the existing selections
12429            new_selections.append(&mut contiguous_row_selections);
12430        }
12431
12432        self.transact(window, cx, |this, window, cx| {
12433            this.unfold_ranges(&unfold_ranges, true, true, cx);
12434            this.buffer.update(cx, |buffer, cx| {
12435                for (range, text) in edits {
12436                    buffer.edit([(range, text)], None, cx);
12437                }
12438            });
12439            this.fold_creases(refold_creases, true, window, cx);
12440            this.change_selections(Default::default(), window, cx, |s| {
12441                s.select(new_selections);
12442            })
12443        });
12444    }
12445
12446    pub fn move_line_down(
12447        &mut self,
12448        _: &MoveLineDown,
12449        window: &mut Window,
12450        cx: &mut Context<Self>,
12451    ) {
12452        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12453        if self.mode.is_single_line() {
12454            cx.propagate();
12455            return;
12456        }
12457
12458        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12459        let buffer = self.buffer.read(cx).snapshot(cx);
12460
12461        let mut edits = Vec::new();
12462        let mut unfold_ranges = Vec::new();
12463        let mut refold_creases = Vec::new();
12464
12465        let selections = self.selections.all::<Point>(&display_map);
12466        let mut selections = selections.iter().peekable();
12467        let mut contiguous_row_selections = Vec::new();
12468        let mut new_selections = Vec::new();
12469
12470        while let Some(selection) = selections.next() {
12471            // Find all the selections that span a contiguous row range
12472            let (start_row, end_row) = consume_contiguous_rows(
12473                &mut contiguous_row_selections,
12474                selection,
12475                &display_map,
12476                &mut selections,
12477            );
12478
12479            // Move the text spanned by the row range to be after the last line of the row range
12480            if end_row.0 <= buffer.max_point().row {
12481                let range_to_move =
12482                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12483                let insertion_point = display_map
12484                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12485                    .0;
12486
12487                // Don't move lines across excerpt boundaries
12488                if buffer
12489                    .excerpt_containing(range_to_move.start..insertion_point)
12490                    .is_some()
12491                {
12492                    let mut text = String::from("\n");
12493                    text.extend(buffer.text_for_range(range_to_move.clone()));
12494                    text.pop(); // Drop trailing newline
12495                    edits.push((
12496                        buffer.anchor_after(range_to_move.start)
12497                            ..buffer.anchor_before(range_to_move.end),
12498                        String::new(),
12499                    ));
12500                    let insertion_anchor = buffer.anchor_after(insertion_point);
12501                    edits.push((insertion_anchor..insertion_anchor, text));
12502
12503                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12504
12505                    // Move selections down
12506                    new_selections.extend(contiguous_row_selections.drain(..).map(
12507                        |mut selection| {
12508                            selection.start.row += row_delta;
12509                            selection.end.row += row_delta;
12510                            selection
12511                        },
12512                    ));
12513
12514                    // Move folds down
12515                    unfold_ranges.push(range_to_move.clone());
12516                    for fold in display_map.folds_in_range(
12517                        buffer.anchor_before(range_to_move.start)
12518                            ..buffer.anchor_after(range_to_move.end),
12519                    ) {
12520                        let mut start = fold.range.start.to_point(&buffer);
12521                        let mut end = fold.range.end.to_point(&buffer);
12522                        start.row += row_delta;
12523                        end.row += row_delta;
12524                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12525                    }
12526                }
12527            }
12528
12529            // If we didn't move line(s), preserve the existing selections
12530            new_selections.append(&mut contiguous_row_selections);
12531        }
12532
12533        self.transact(window, cx, |this, window, cx| {
12534            this.unfold_ranges(&unfold_ranges, true, true, cx);
12535            this.buffer.update(cx, |buffer, cx| {
12536                for (range, text) in edits {
12537                    buffer.edit([(range, text)], None, cx);
12538                }
12539            });
12540            this.fold_creases(refold_creases, true, window, cx);
12541            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12542        });
12543    }
12544
12545    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12546        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12547        let text_layout_details = &self.text_layout_details(window);
12548        self.transact(window, cx, |this, window, cx| {
12549            let edits = this.change_selections(Default::default(), window, cx, |s| {
12550                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12551                s.move_with(|display_map, selection| {
12552                    if !selection.is_empty() {
12553                        return;
12554                    }
12555
12556                    let mut head = selection.head();
12557                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12558                    if head.column() == display_map.line_len(head.row()) {
12559                        transpose_offset = display_map
12560                            .buffer_snapshot()
12561                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12562                    }
12563
12564                    if transpose_offset == MultiBufferOffset(0) {
12565                        return;
12566                    }
12567
12568                    *head.column_mut() += 1;
12569                    head = display_map.clip_point(head, Bias::Right);
12570                    let goal = SelectionGoal::HorizontalPosition(
12571                        display_map
12572                            .x_for_display_point(head, text_layout_details)
12573                            .into(),
12574                    );
12575                    selection.collapse_to(head, goal);
12576
12577                    let transpose_start = display_map
12578                        .buffer_snapshot()
12579                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12580                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12581                        let transpose_end = display_map
12582                            .buffer_snapshot()
12583                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12584                        if let Some(ch) = display_map
12585                            .buffer_snapshot()
12586                            .chars_at(transpose_start)
12587                            .next()
12588                        {
12589                            edits.push((transpose_start..transpose_offset, String::new()));
12590                            edits.push((transpose_end..transpose_end, ch.to_string()));
12591                        }
12592                    }
12593                });
12594                edits
12595            });
12596            this.buffer
12597                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12598            let selections = this
12599                .selections
12600                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12601            this.change_selections(Default::default(), window, cx, |s| {
12602                s.select(selections);
12603            });
12604        });
12605    }
12606
12607    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12608        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12609        if self.mode.is_single_line() {
12610            cx.propagate();
12611            return;
12612        }
12613
12614        self.rewrap_impl(RewrapOptions::default(), cx)
12615    }
12616
12617    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12618        let buffer = self.buffer.read(cx).snapshot(cx);
12619        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12620
12621        #[derive(Clone, Debug, PartialEq)]
12622        enum CommentFormat {
12623            /// single line comment, with prefix for line
12624            Line(String),
12625            /// single line within a block comment, with prefix for line
12626            BlockLine(String),
12627            /// a single line of a block comment that includes the initial delimiter
12628            BlockCommentWithStart(BlockCommentConfig),
12629            /// a single line of a block comment that includes the ending delimiter
12630            BlockCommentWithEnd(BlockCommentConfig),
12631        }
12632
12633        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12634        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12635            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12636                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12637                .peekable();
12638
12639            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12640                row
12641            } else {
12642                return Vec::new();
12643            };
12644
12645            let language_settings = buffer.language_settings_at(selection.head(), cx);
12646            let language_scope = buffer.language_scope_at(selection.head());
12647
12648            let indent_and_prefix_for_row =
12649                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12650                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12651                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12652                        &language_scope
12653                    {
12654                        let indent_end = Point::new(row, indent.len);
12655                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12656                        let line_text_after_indent = buffer
12657                            .text_for_range(indent_end..line_end)
12658                            .collect::<String>();
12659
12660                        let is_within_comment_override = buffer
12661                            .language_scope_at(indent_end)
12662                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12663                        let comment_delimiters = if is_within_comment_override {
12664                            // we are within a comment syntax node, but we don't
12665                            // yet know what kind of comment: block, doc or line
12666                            match (
12667                                language_scope.documentation_comment(),
12668                                language_scope.block_comment(),
12669                            ) {
12670                                (Some(config), _) | (_, Some(config))
12671                                    if buffer.contains_str_at(indent_end, &config.start) =>
12672                                {
12673                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12674                                }
12675                                (Some(config), _) | (_, Some(config))
12676                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12677                                {
12678                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12679                                }
12680                                (Some(config), _) | (_, Some(config))
12681                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12682                                {
12683                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12684                                }
12685                                (_, _) => language_scope
12686                                    .line_comment_prefixes()
12687                                    .iter()
12688                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12689                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12690                            }
12691                        } else {
12692                            // we not in an overridden comment node, but we may
12693                            // be within a non-overridden line comment node
12694                            language_scope
12695                                .line_comment_prefixes()
12696                                .iter()
12697                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12698                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12699                        };
12700
12701                        let rewrap_prefix = language_scope
12702                            .rewrap_prefixes()
12703                            .iter()
12704                            .find_map(|prefix_regex| {
12705                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12706                                    if mat.start() == 0 {
12707                                        Some(mat.as_str().to_string())
12708                                    } else {
12709                                        None
12710                                    }
12711                                })
12712                            })
12713                            .flatten();
12714                        (comment_delimiters, rewrap_prefix)
12715                    } else {
12716                        (None, None)
12717                    };
12718                    (indent, comment_prefix, rewrap_prefix)
12719                };
12720
12721            let mut ranges = Vec::new();
12722            let from_empty_selection = selection.is_empty();
12723
12724            let mut current_range_start = first_row;
12725            let mut prev_row = first_row;
12726            let (
12727                mut current_range_indent,
12728                mut current_range_comment_delimiters,
12729                mut current_range_rewrap_prefix,
12730            ) = indent_and_prefix_for_row(first_row);
12731
12732            for row in non_blank_rows_iter.skip(1) {
12733                let has_paragraph_break = row > prev_row + 1;
12734
12735                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12736                    indent_and_prefix_for_row(row);
12737
12738                let has_indent_change = row_indent != current_range_indent;
12739                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12740
12741                let has_boundary_change = has_comment_change
12742                    || row_rewrap_prefix.is_some()
12743                    || (has_indent_change && current_range_comment_delimiters.is_some());
12744
12745                if has_paragraph_break || has_boundary_change {
12746                    ranges.push((
12747                        language_settings.clone(),
12748                        Point::new(current_range_start, 0)
12749                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12750                        current_range_indent,
12751                        current_range_comment_delimiters.clone(),
12752                        current_range_rewrap_prefix.clone(),
12753                        from_empty_selection,
12754                    ));
12755                    current_range_start = row;
12756                    current_range_indent = row_indent;
12757                    current_range_comment_delimiters = row_comment_delimiters;
12758                    current_range_rewrap_prefix = row_rewrap_prefix;
12759                }
12760                prev_row = row;
12761            }
12762
12763            ranges.push((
12764                language_settings.clone(),
12765                Point::new(current_range_start, 0)
12766                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12767                current_range_indent,
12768                current_range_comment_delimiters,
12769                current_range_rewrap_prefix,
12770                from_empty_selection,
12771            ));
12772
12773            ranges
12774        });
12775
12776        let mut edits = Vec::new();
12777        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12778
12779        for (
12780            language_settings,
12781            wrap_range,
12782            mut indent_size,
12783            comment_prefix,
12784            rewrap_prefix,
12785            from_empty_selection,
12786        ) in wrap_ranges
12787        {
12788            let mut start_row = wrap_range.start.row;
12789            let mut end_row = wrap_range.end.row;
12790
12791            // Skip selections that overlap with a range that has already been rewrapped.
12792            let selection_range = start_row..end_row;
12793            if rewrapped_row_ranges
12794                .iter()
12795                .any(|range| range.overlaps(&selection_range))
12796            {
12797                continue;
12798            }
12799
12800            let tab_size = language_settings.tab_size;
12801
12802            let (line_prefix, inside_comment) = match &comment_prefix {
12803                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12804                    (Some(prefix.as_str()), true)
12805                }
12806                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12807                    (Some(prefix.as_ref()), true)
12808                }
12809                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12810                    start: _,
12811                    end: _,
12812                    prefix,
12813                    tab_size,
12814                })) => {
12815                    indent_size.len += tab_size;
12816                    (Some(prefix.as_ref()), true)
12817                }
12818                None => (None, false),
12819            };
12820            let indent_prefix = indent_size.chars().collect::<String>();
12821            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12822
12823            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12824                RewrapBehavior::InComments => inside_comment,
12825                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12826                RewrapBehavior::Anywhere => true,
12827            };
12828
12829            let should_rewrap = options.override_language_settings
12830                || allow_rewrap_based_on_language
12831                || self.hard_wrap.is_some();
12832            if !should_rewrap {
12833                continue;
12834            }
12835
12836            if from_empty_selection {
12837                'expand_upwards: while start_row > 0 {
12838                    let prev_row = start_row - 1;
12839                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12840                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12841                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12842                    {
12843                        start_row = prev_row;
12844                    } else {
12845                        break 'expand_upwards;
12846                    }
12847                }
12848
12849                'expand_downwards: while end_row < buffer.max_point().row {
12850                    let next_row = end_row + 1;
12851                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12852                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12853                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12854                    {
12855                        end_row = next_row;
12856                    } else {
12857                        break 'expand_downwards;
12858                    }
12859                }
12860            }
12861
12862            let start = Point::new(start_row, 0);
12863            let start_offset = ToOffset::to_offset(&start, &buffer);
12864            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12865            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12866            let mut first_line_delimiter = None;
12867            let mut last_line_delimiter = None;
12868            let Some(lines_without_prefixes) = selection_text
12869                .lines()
12870                .enumerate()
12871                .map(|(ix, line)| {
12872                    let line_trimmed = line.trim_start();
12873                    if rewrap_prefix.is_some() && ix > 0 {
12874                        Ok(line_trimmed)
12875                    } else if let Some(
12876                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12877                            start,
12878                            prefix,
12879                            end,
12880                            tab_size,
12881                        })
12882                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12883                            start,
12884                            prefix,
12885                            end,
12886                            tab_size,
12887                        }),
12888                    ) = &comment_prefix
12889                    {
12890                        let line_trimmed = line_trimmed
12891                            .strip_prefix(start.as_ref())
12892                            .map(|s| {
12893                                let mut indent_size = indent_size;
12894                                indent_size.len -= tab_size;
12895                                let indent_prefix: String = indent_size.chars().collect();
12896                                first_line_delimiter = Some((indent_prefix, start));
12897                                s.trim_start()
12898                            })
12899                            .unwrap_or(line_trimmed);
12900                        let line_trimmed = line_trimmed
12901                            .strip_suffix(end.as_ref())
12902                            .map(|s| {
12903                                last_line_delimiter = Some(end);
12904                                s.trim_end()
12905                            })
12906                            .unwrap_or(line_trimmed);
12907                        let line_trimmed = line_trimmed
12908                            .strip_prefix(prefix.as_ref())
12909                            .unwrap_or(line_trimmed);
12910                        Ok(line_trimmed)
12911                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12912                        line_trimmed.strip_prefix(prefix).with_context(|| {
12913                            format!("line did not start with prefix {prefix:?}: {line:?}")
12914                        })
12915                    } else {
12916                        line_trimmed
12917                            .strip_prefix(&line_prefix.trim_start())
12918                            .with_context(|| {
12919                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12920                            })
12921                    }
12922                })
12923                .collect::<Result<Vec<_>, _>>()
12924                .log_err()
12925            else {
12926                continue;
12927            };
12928
12929            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12930                buffer
12931                    .language_settings_at(Point::new(start_row, 0), cx)
12932                    .preferred_line_length as usize
12933            });
12934
12935            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12936                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12937            } else {
12938                line_prefix.clone()
12939            };
12940
12941            let wrapped_text = {
12942                let mut wrapped_text = wrap_with_prefix(
12943                    line_prefix,
12944                    subsequent_lines_prefix,
12945                    lines_without_prefixes.join("\n"),
12946                    wrap_column,
12947                    tab_size,
12948                    options.preserve_existing_whitespace,
12949                );
12950
12951                if let Some((indent, delimiter)) = first_line_delimiter {
12952                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12953                }
12954                if let Some(last_line) = last_line_delimiter {
12955                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12956                }
12957
12958                wrapped_text
12959            };
12960
12961            // TODO: should always use char-based diff while still supporting cursor behavior that
12962            // matches vim.
12963            let mut diff_options = DiffOptions::default();
12964            if options.override_language_settings {
12965                diff_options.max_word_diff_len = 0;
12966                diff_options.max_word_diff_line_count = 0;
12967            } else {
12968                diff_options.max_word_diff_len = usize::MAX;
12969                diff_options.max_word_diff_line_count = usize::MAX;
12970            }
12971
12972            for (old_range, new_text) in
12973                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12974            {
12975                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12976                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12977                edits.push((edit_start..edit_end, new_text));
12978            }
12979
12980            rewrapped_row_ranges.push(start_row..=end_row);
12981        }
12982
12983        self.buffer
12984            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12985    }
12986
12987    pub fn cut_common(
12988        &mut self,
12989        cut_no_selection_line: bool,
12990        window: &mut Window,
12991        cx: &mut Context<Self>,
12992    ) -> ClipboardItem {
12993        let mut text = String::new();
12994        let buffer = self.buffer.read(cx).snapshot(cx);
12995        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12996        let mut clipboard_selections = Vec::with_capacity(selections.len());
12997        {
12998            let max_point = buffer.max_point();
12999            let mut is_first = true;
13000            let mut prev_selection_was_entire_line = false;
13001            for selection in &mut selections {
13002                let is_entire_line =
13003                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13004                if is_entire_line {
13005                    selection.start = Point::new(selection.start.row, 0);
13006                    if !selection.is_empty() && selection.end.column == 0 {
13007                        selection.end = cmp::min(max_point, selection.end);
13008                    } else {
13009                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13010                    }
13011                    selection.goal = SelectionGoal::None;
13012                }
13013                if is_first {
13014                    is_first = false;
13015                } else if !prev_selection_was_entire_line {
13016                    text += "\n";
13017                }
13018                prev_selection_was_entire_line = is_entire_line;
13019                let mut len = 0;
13020                for chunk in buffer.text_for_range(selection.start..selection.end) {
13021                    text.push_str(chunk);
13022                    len += chunk.len();
13023                }
13024
13025                clipboard_selections.push(ClipboardSelection::for_buffer(
13026                    len,
13027                    is_entire_line,
13028                    selection.range(),
13029                    &buffer,
13030                    self.project.as_ref(),
13031                    cx,
13032                ));
13033            }
13034        }
13035
13036        self.transact(window, cx, |this, window, cx| {
13037            this.change_selections(Default::default(), window, cx, |s| {
13038                s.select(selections);
13039            });
13040            this.insert("", window, cx);
13041        });
13042        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13043    }
13044
13045    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13046        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13047        let item = self.cut_common(true, window, cx);
13048        cx.write_to_clipboard(item);
13049    }
13050
13051    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13052        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13053        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13054            s.move_with(|snapshot, sel| {
13055                if sel.is_empty() {
13056                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13057                }
13058                if sel.is_empty() {
13059                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13060                }
13061            });
13062        });
13063        let item = self.cut_common(false, window, cx);
13064        cx.set_global(KillRing(item))
13065    }
13066
13067    pub fn kill_ring_yank(
13068        &mut self,
13069        _: &KillRingYank,
13070        window: &mut Window,
13071        cx: &mut Context<Self>,
13072    ) {
13073        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13074        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13075            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13076                (kill_ring.text().to_string(), kill_ring.metadata_json())
13077            } else {
13078                return;
13079            }
13080        } else {
13081            return;
13082        };
13083        self.do_paste(&text, metadata, false, window, cx);
13084    }
13085
13086    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13087        self.do_copy(true, cx);
13088    }
13089
13090    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13091        self.do_copy(false, cx);
13092    }
13093
13094    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13095        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13096        let buffer = self.buffer.read(cx).read(cx);
13097        let mut text = String::new();
13098
13099        let mut clipboard_selections = Vec::with_capacity(selections.len());
13100        {
13101            let max_point = buffer.max_point();
13102            let mut is_first = true;
13103            let mut prev_selection_was_entire_line = false;
13104            for selection in &selections {
13105                let mut start = selection.start;
13106                let mut end = selection.end;
13107                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13108                let mut add_trailing_newline = false;
13109                if is_entire_line {
13110                    start = Point::new(start.row, 0);
13111                    let next_line_start = Point::new(end.row + 1, 0);
13112                    if next_line_start <= max_point {
13113                        end = next_line_start;
13114                    } else {
13115                        // We're on the last line without a trailing newline.
13116                        // Copy to the end of the line and add a newline afterwards.
13117                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13118                        add_trailing_newline = true;
13119                    }
13120                }
13121
13122                let mut trimmed_selections = Vec::new();
13123                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13124                    let row = MultiBufferRow(start.row);
13125                    let first_indent = buffer.indent_size_for_line(row);
13126                    if first_indent.len == 0 || start.column > first_indent.len {
13127                        trimmed_selections.push(start..end);
13128                    } else {
13129                        trimmed_selections.push(
13130                            Point::new(row.0, first_indent.len)
13131                                ..Point::new(row.0, buffer.line_len(row)),
13132                        );
13133                        for row in start.row + 1..=end.row {
13134                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13135                            if row == end.row {
13136                                line_len = end.column;
13137                            }
13138                            if line_len == 0 {
13139                                trimmed_selections
13140                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13141                                continue;
13142                            }
13143                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13144                            if row_indent_size.len >= first_indent.len {
13145                                trimmed_selections.push(
13146                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13147                                );
13148                            } else {
13149                                trimmed_selections.clear();
13150                                trimmed_selections.push(start..end);
13151                                break;
13152                            }
13153                        }
13154                    }
13155                } else {
13156                    trimmed_selections.push(start..end);
13157                }
13158
13159                for trimmed_range in trimmed_selections {
13160                    if is_first {
13161                        is_first = false;
13162                    } else if !prev_selection_was_entire_line {
13163                        text += "\n";
13164                    }
13165                    prev_selection_was_entire_line = is_entire_line;
13166                    let mut len = 0;
13167                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13168                        text.push_str(chunk);
13169                        len += chunk.len();
13170                    }
13171                    if add_trailing_newline {
13172                        text.push('\n');
13173                        len += 1;
13174                    }
13175                    clipboard_selections.push(ClipboardSelection::for_buffer(
13176                        len,
13177                        is_entire_line,
13178                        trimmed_range,
13179                        &buffer,
13180                        self.project.as_ref(),
13181                        cx,
13182                    ));
13183                }
13184            }
13185        }
13186
13187        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13188            text,
13189            clipboard_selections,
13190        ));
13191    }
13192
13193    pub fn do_paste(
13194        &mut self,
13195        text: &String,
13196        clipboard_selections: Option<Vec<ClipboardSelection>>,
13197        handle_entire_lines: bool,
13198        window: &mut Window,
13199        cx: &mut Context<Self>,
13200    ) {
13201        if self.read_only(cx) {
13202            return;
13203        }
13204
13205        let clipboard_text = Cow::Borrowed(text.as_str());
13206
13207        self.transact(window, cx, |this, window, cx| {
13208            let had_active_edit_prediction = this.has_active_edit_prediction();
13209            let display_map = this.display_snapshot(cx);
13210            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13211            let cursor_offset = this
13212                .selections
13213                .last::<MultiBufferOffset>(&display_map)
13214                .head();
13215
13216            if let Some(mut clipboard_selections) = clipboard_selections {
13217                let all_selections_were_entire_line =
13218                    clipboard_selections.iter().all(|s| s.is_entire_line);
13219                let first_selection_indent_column =
13220                    clipboard_selections.first().map(|s| s.first_line_indent);
13221                if clipboard_selections.len() != old_selections.len() {
13222                    clipboard_selections.drain(..);
13223                }
13224                let mut auto_indent_on_paste = true;
13225
13226                this.buffer.update(cx, |buffer, cx| {
13227                    let snapshot = buffer.read(cx);
13228                    auto_indent_on_paste = snapshot
13229                        .language_settings_at(cursor_offset, cx)
13230                        .auto_indent_on_paste;
13231
13232                    let mut start_offset = 0;
13233                    let mut edits = Vec::new();
13234                    let mut original_indent_columns = Vec::new();
13235                    for (ix, selection) in old_selections.iter().enumerate() {
13236                        let to_insert;
13237                        let entire_line;
13238                        let original_indent_column;
13239                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13240                            let end_offset = start_offset + clipboard_selection.len;
13241                            to_insert = &clipboard_text[start_offset..end_offset];
13242                            entire_line = clipboard_selection.is_entire_line;
13243                            start_offset = if entire_line {
13244                                end_offset
13245                            } else {
13246                                end_offset + 1
13247                            };
13248                            original_indent_column = Some(clipboard_selection.first_line_indent);
13249                        } else {
13250                            to_insert = &*clipboard_text;
13251                            entire_line = all_selections_were_entire_line;
13252                            original_indent_column = first_selection_indent_column
13253                        }
13254
13255                        let (range, to_insert) =
13256                            if selection.is_empty() && handle_entire_lines && entire_line {
13257                                // If the corresponding selection was empty when this slice of the
13258                                // clipboard text was written, then the entire line containing the
13259                                // selection was copied. If this selection is also currently empty,
13260                                // then paste the line before the current line of the buffer.
13261                                let column = selection.start.to_point(&snapshot).column as usize;
13262                                let line_start = selection.start - column;
13263                                (line_start..line_start, Cow::Borrowed(to_insert))
13264                            } else {
13265                                let language = snapshot.language_at(selection.head());
13266                                let range = selection.range();
13267                                if let Some(language) = language
13268                                    && language.name() == "Markdown".into()
13269                                {
13270                                    edit_for_markdown_paste(
13271                                        &snapshot,
13272                                        range,
13273                                        to_insert,
13274                                        url::Url::parse(to_insert).ok(),
13275                                    )
13276                                } else {
13277                                    (range, Cow::Borrowed(to_insert))
13278                                }
13279                            };
13280
13281                        edits.push((range, to_insert));
13282                        original_indent_columns.push(original_indent_column);
13283                    }
13284                    drop(snapshot);
13285
13286                    buffer.edit(
13287                        edits,
13288                        if auto_indent_on_paste {
13289                            Some(AutoindentMode::Block {
13290                                original_indent_columns,
13291                            })
13292                        } else {
13293                            None
13294                        },
13295                        cx,
13296                    );
13297                });
13298
13299                let selections = this
13300                    .selections
13301                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13302                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13303            } else {
13304                let url = url::Url::parse(&clipboard_text).ok();
13305
13306                let auto_indent_mode = if !clipboard_text.is_empty() {
13307                    Some(AutoindentMode::Block {
13308                        original_indent_columns: Vec::new(),
13309                    })
13310                } else {
13311                    None
13312                };
13313
13314                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13315                    let snapshot = buffer.snapshot(cx);
13316
13317                    let anchors = old_selections
13318                        .iter()
13319                        .map(|s| {
13320                            let anchor = snapshot.anchor_after(s.head());
13321                            s.map(|_| anchor)
13322                        })
13323                        .collect::<Vec<_>>();
13324
13325                    let mut edits = Vec::new();
13326
13327                    for selection in old_selections.iter() {
13328                        let language = snapshot.language_at(selection.head());
13329                        let range = selection.range();
13330
13331                        let (edit_range, edit_text) = if let Some(language) = language
13332                            && language.name() == "Markdown".into()
13333                        {
13334                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13335                        } else {
13336                            (range, clipboard_text.clone())
13337                        };
13338
13339                        edits.push((edit_range, edit_text));
13340                    }
13341
13342                    drop(snapshot);
13343                    buffer.edit(edits, auto_indent_mode, cx);
13344
13345                    anchors
13346                });
13347
13348                this.change_selections(Default::default(), window, cx, |s| {
13349                    s.select_anchors(selection_anchors);
13350                });
13351            }
13352
13353            //   🤔                 |    ..     | show_in_menu |
13354            // | ..                  |   true        true
13355            // | had_edit_prediction |   false       true
13356
13357            let trigger_in_words =
13358                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13359
13360            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13361        });
13362    }
13363
13364    pub fn diff_clipboard_with_selection(
13365        &mut self,
13366        _: &DiffClipboardWithSelection,
13367        window: &mut Window,
13368        cx: &mut Context<Self>,
13369    ) {
13370        let selections = self
13371            .selections
13372            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13373
13374        if selections.is_empty() {
13375            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13376            return;
13377        };
13378
13379        let clipboard_text = match cx.read_from_clipboard() {
13380            Some(item) => match item.entries().first() {
13381                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13382                _ => None,
13383            },
13384            None => None,
13385        };
13386
13387        let Some(clipboard_text) = clipboard_text else {
13388            log::warn!("Clipboard doesn't contain text.");
13389            return;
13390        };
13391
13392        window.dispatch_action(
13393            Box::new(DiffClipboardWithSelectionData {
13394                clipboard_text,
13395                editor: cx.entity(),
13396            }),
13397            cx,
13398        );
13399    }
13400
13401    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13402        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13403        if let Some(item) = cx.read_from_clipboard() {
13404            let entries = item.entries();
13405
13406            match entries.first() {
13407                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13408                // of all the pasted entries.
13409                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13410                    .do_paste(
13411                        clipboard_string.text(),
13412                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13413                        true,
13414                        window,
13415                        cx,
13416                    ),
13417                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13418            }
13419        }
13420    }
13421
13422    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13423        if self.read_only(cx) {
13424            return;
13425        }
13426
13427        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13428
13429        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13430            if let Some((selections, _)) =
13431                self.selection_history.transaction(transaction_id).cloned()
13432            {
13433                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13434                    s.select_anchors(selections.to_vec());
13435                });
13436            } else {
13437                log::error!(
13438                    "No entry in selection_history found for undo. \
13439                     This may correspond to a bug where undo does not update the selection. \
13440                     If this is occurring, please add details to \
13441                     https://github.com/zed-industries/zed/issues/22692"
13442                );
13443            }
13444            self.request_autoscroll(Autoscroll::fit(), cx);
13445            self.unmark_text(window, cx);
13446            self.refresh_edit_prediction(true, false, window, cx);
13447            cx.emit(EditorEvent::Edited { transaction_id });
13448            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13449        }
13450    }
13451
13452    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13453        if self.read_only(cx) {
13454            return;
13455        }
13456
13457        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13458
13459        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13460            if let Some((_, Some(selections))) =
13461                self.selection_history.transaction(transaction_id).cloned()
13462            {
13463                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13464                    s.select_anchors(selections.to_vec());
13465                });
13466            } else {
13467                log::error!(
13468                    "No entry in selection_history found for redo. \
13469                     This may correspond to a bug where undo does not update the selection. \
13470                     If this is occurring, please add details to \
13471                     https://github.com/zed-industries/zed/issues/22692"
13472                );
13473            }
13474            self.request_autoscroll(Autoscroll::fit(), cx);
13475            self.unmark_text(window, cx);
13476            self.refresh_edit_prediction(true, false, window, cx);
13477            cx.emit(EditorEvent::Edited { transaction_id });
13478        }
13479    }
13480
13481    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13482        self.buffer
13483            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13484    }
13485
13486    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13487        self.buffer
13488            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13489    }
13490
13491    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13492        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13493        self.change_selections(Default::default(), window, cx, |s| {
13494            s.move_with(|map, selection| {
13495                let cursor = if selection.is_empty() {
13496                    movement::left(map, selection.start)
13497                } else {
13498                    selection.start
13499                };
13500                selection.collapse_to(cursor, SelectionGoal::None);
13501            });
13502        })
13503    }
13504
13505    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13507        self.change_selections(Default::default(), window, cx, |s| {
13508            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13509        })
13510    }
13511
13512    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13513        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13514        self.change_selections(Default::default(), window, cx, |s| {
13515            s.move_with(|map, selection| {
13516                let cursor = if selection.is_empty() {
13517                    movement::right(map, selection.end)
13518                } else {
13519                    selection.end
13520                };
13521                selection.collapse_to(cursor, SelectionGoal::None)
13522            });
13523        })
13524    }
13525
13526    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13527        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13528        self.change_selections(Default::default(), window, cx, |s| {
13529            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13530        });
13531    }
13532
13533    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13534        if self.take_rename(true, window, cx).is_some() {
13535            return;
13536        }
13537
13538        if self.mode.is_single_line() {
13539            cx.propagate();
13540            return;
13541        }
13542
13543        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13544
13545        let text_layout_details = &self.text_layout_details(window);
13546        let selection_count = self.selections.count();
13547        let first_selection = self.selections.first_anchor();
13548
13549        self.change_selections(Default::default(), window, cx, |s| {
13550            s.move_with(|map, selection| {
13551                if !selection.is_empty() {
13552                    selection.goal = SelectionGoal::None;
13553                }
13554                let (cursor, goal) = movement::up(
13555                    map,
13556                    selection.start,
13557                    selection.goal,
13558                    false,
13559                    text_layout_details,
13560                );
13561                selection.collapse_to(cursor, goal);
13562            });
13563        });
13564
13565        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13566        {
13567            cx.propagate();
13568        }
13569    }
13570
13571    pub fn move_up_by_lines(
13572        &mut self,
13573        action: &MoveUpByLines,
13574        window: &mut Window,
13575        cx: &mut Context<Self>,
13576    ) {
13577        if self.take_rename(true, window, cx).is_some() {
13578            return;
13579        }
13580
13581        if self.mode.is_single_line() {
13582            cx.propagate();
13583            return;
13584        }
13585
13586        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13587
13588        let text_layout_details = &self.text_layout_details(window);
13589
13590        self.change_selections(Default::default(), window, cx, |s| {
13591            s.move_with(|map, selection| {
13592                if !selection.is_empty() {
13593                    selection.goal = SelectionGoal::None;
13594                }
13595                let (cursor, goal) = movement::up_by_rows(
13596                    map,
13597                    selection.start,
13598                    action.lines,
13599                    selection.goal,
13600                    false,
13601                    text_layout_details,
13602                );
13603                selection.collapse_to(cursor, goal);
13604            });
13605        })
13606    }
13607
13608    pub fn move_down_by_lines(
13609        &mut self,
13610        action: &MoveDownByLines,
13611        window: &mut Window,
13612        cx: &mut Context<Self>,
13613    ) {
13614        if self.take_rename(true, window, cx).is_some() {
13615            return;
13616        }
13617
13618        if self.mode.is_single_line() {
13619            cx.propagate();
13620            return;
13621        }
13622
13623        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13624
13625        let text_layout_details = &self.text_layout_details(window);
13626
13627        self.change_selections(Default::default(), window, cx, |s| {
13628            s.move_with(|map, selection| {
13629                if !selection.is_empty() {
13630                    selection.goal = SelectionGoal::None;
13631                }
13632                let (cursor, goal) = movement::down_by_rows(
13633                    map,
13634                    selection.start,
13635                    action.lines,
13636                    selection.goal,
13637                    false,
13638                    text_layout_details,
13639                );
13640                selection.collapse_to(cursor, goal);
13641            });
13642        })
13643    }
13644
13645    pub fn select_down_by_lines(
13646        &mut self,
13647        action: &SelectDownByLines,
13648        window: &mut Window,
13649        cx: &mut Context<Self>,
13650    ) {
13651        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13652        let text_layout_details = &self.text_layout_details(window);
13653        self.change_selections(Default::default(), window, cx, |s| {
13654            s.move_heads_with(|map, head, goal| {
13655                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13656            })
13657        })
13658    }
13659
13660    pub fn select_up_by_lines(
13661        &mut self,
13662        action: &SelectUpByLines,
13663        window: &mut Window,
13664        cx: &mut Context<Self>,
13665    ) {
13666        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13667        let text_layout_details = &self.text_layout_details(window);
13668        self.change_selections(Default::default(), window, cx, |s| {
13669            s.move_heads_with(|map, head, goal| {
13670                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13671            })
13672        })
13673    }
13674
13675    pub fn select_page_up(
13676        &mut self,
13677        _: &SelectPageUp,
13678        window: &mut Window,
13679        cx: &mut Context<Self>,
13680    ) {
13681        let Some(row_count) = self.visible_row_count() else {
13682            return;
13683        };
13684
13685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13686
13687        let text_layout_details = &self.text_layout_details(window);
13688
13689        self.change_selections(Default::default(), window, cx, |s| {
13690            s.move_heads_with(|map, head, goal| {
13691                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13692            })
13693        })
13694    }
13695
13696    pub fn move_page_up(
13697        &mut self,
13698        action: &MovePageUp,
13699        window: &mut Window,
13700        cx: &mut Context<Self>,
13701    ) {
13702        if self.take_rename(true, window, cx).is_some() {
13703            return;
13704        }
13705
13706        if self
13707            .context_menu
13708            .borrow_mut()
13709            .as_mut()
13710            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13711            .unwrap_or(false)
13712        {
13713            return;
13714        }
13715
13716        if matches!(self.mode, EditorMode::SingleLine) {
13717            cx.propagate();
13718            return;
13719        }
13720
13721        let Some(row_count) = self.visible_row_count() else {
13722            return;
13723        };
13724
13725        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13726
13727        let effects = if action.center_cursor {
13728            SelectionEffects::scroll(Autoscroll::center())
13729        } else {
13730            SelectionEffects::default()
13731        };
13732
13733        let text_layout_details = &self.text_layout_details(window);
13734
13735        self.change_selections(effects, 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::up_by_rows(
13741                    map,
13742                    selection.end,
13743                    row_count,
13744                    selection.goal,
13745                    false,
13746                    text_layout_details,
13747                );
13748                selection.collapse_to(cursor, goal);
13749            });
13750        });
13751    }
13752
13753    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13754        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13755        let text_layout_details = &self.text_layout_details(window);
13756        self.change_selections(Default::default(), window, cx, |s| {
13757            s.move_heads_with(|map, head, goal| {
13758                movement::up(map, head, goal, false, text_layout_details)
13759            })
13760        })
13761    }
13762
13763    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13764        self.take_rename(true, window, cx);
13765
13766        if self.mode.is_single_line() {
13767            cx.propagate();
13768            return;
13769        }
13770
13771        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13772
13773        let text_layout_details = &self.text_layout_details(window);
13774        let selection_count = self.selections.count();
13775        let first_selection = self.selections.first_anchor();
13776
13777        self.change_selections(Default::default(), window, cx, |s| {
13778            s.move_with(|map, selection| {
13779                if !selection.is_empty() {
13780                    selection.goal = SelectionGoal::None;
13781                }
13782                let (cursor, goal) = movement::down(
13783                    map,
13784                    selection.end,
13785                    selection.goal,
13786                    false,
13787                    text_layout_details,
13788                );
13789                selection.collapse_to(cursor, goal);
13790            });
13791        });
13792
13793        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13794        {
13795            cx.propagate();
13796        }
13797    }
13798
13799    pub fn select_page_down(
13800        &mut self,
13801        _: &SelectPageDown,
13802        window: &mut Window,
13803        cx: &mut Context<Self>,
13804    ) {
13805        let Some(row_count) = self.visible_row_count() else {
13806            return;
13807        };
13808
13809        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13810
13811        let text_layout_details = &self.text_layout_details(window);
13812
13813        self.change_selections(Default::default(), window, cx, |s| {
13814            s.move_heads_with(|map, head, goal| {
13815                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13816            })
13817        })
13818    }
13819
13820    pub fn move_page_down(
13821        &mut self,
13822        action: &MovePageDown,
13823        window: &mut Window,
13824        cx: &mut Context<Self>,
13825    ) {
13826        if self.take_rename(true, window, cx).is_some() {
13827            return;
13828        }
13829
13830        if self
13831            .context_menu
13832            .borrow_mut()
13833            .as_mut()
13834            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13835            .unwrap_or(false)
13836        {
13837            return;
13838        }
13839
13840        if matches!(self.mode, EditorMode::SingleLine) {
13841            cx.propagate();
13842            return;
13843        }
13844
13845        let Some(row_count) = self.visible_row_count() else {
13846            return;
13847        };
13848
13849        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13850
13851        let effects = if action.center_cursor {
13852            SelectionEffects::scroll(Autoscroll::center())
13853        } else {
13854            SelectionEffects::default()
13855        };
13856
13857        let text_layout_details = &self.text_layout_details(window);
13858        self.change_selections(effects, window, cx, |s| {
13859            s.move_with(|map, selection| {
13860                if !selection.is_empty() {
13861                    selection.goal = SelectionGoal::None;
13862                }
13863                let (cursor, goal) = movement::down_by_rows(
13864                    map,
13865                    selection.end,
13866                    row_count,
13867                    selection.goal,
13868                    false,
13869                    text_layout_details,
13870                );
13871                selection.collapse_to(cursor, goal);
13872            });
13873        });
13874    }
13875
13876    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13877        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13878        let text_layout_details = &self.text_layout_details(window);
13879        self.change_selections(Default::default(), window, cx, |s| {
13880            s.move_heads_with(|map, head, goal| {
13881                movement::down(map, head, goal, false, text_layout_details)
13882            })
13883        });
13884    }
13885
13886    pub fn context_menu_first(
13887        &mut self,
13888        _: &ContextMenuFirst,
13889        window: &mut Window,
13890        cx: &mut Context<Self>,
13891    ) {
13892        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13893            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13894        }
13895    }
13896
13897    pub fn context_menu_prev(
13898        &mut self,
13899        _: &ContextMenuPrevious,
13900        window: &mut Window,
13901        cx: &mut Context<Self>,
13902    ) {
13903        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13904            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13905        }
13906    }
13907
13908    pub fn context_menu_next(
13909        &mut self,
13910        _: &ContextMenuNext,
13911        window: &mut Window,
13912        cx: &mut Context<Self>,
13913    ) {
13914        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13915            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13916        }
13917    }
13918
13919    pub fn context_menu_last(
13920        &mut self,
13921        _: &ContextMenuLast,
13922        window: &mut Window,
13923        cx: &mut Context<Self>,
13924    ) {
13925        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13926            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13927        }
13928    }
13929
13930    pub fn signature_help_prev(
13931        &mut self,
13932        _: &SignatureHelpPrevious,
13933        _: &mut Window,
13934        cx: &mut Context<Self>,
13935    ) {
13936        if let Some(popover) = self.signature_help_state.popover_mut() {
13937            if popover.current_signature == 0 {
13938                popover.current_signature = popover.signatures.len() - 1;
13939            } else {
13940                popover.current_signature -= 1;
13941            }
13942            cx.notify();
13943        }
13944    }
13945
13946    pub fn signature_help_next(
13947        &mut self,
13948        _: &SignatureHelpNext,
13949        _: &mut Window,
13950        cx: &mut Context<Self>,
13951    ) {
13952        if let Some(popover) = self.signature_help_state.popover_mut() {
13953            if popover.current_signature + 1 == popover.signatures.len() {
13954                popover.current_signature = 0;
13955            } else {
13956                popover.current_signature += 1;
13957            }
13958            cx.notify();
13959        }
13960    }
13961
13962    pub fn move_to_previous_word_start(
13963        &mut self,
13964        _: &MoveToPreviousWordStart,
13965        window: &mut Window,
13966        cx: &mut Context<Self>,
13967    ) {
13968        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13969        self.change_selections(Default::default(), window, cx, |s| {
13970            s.move_cursors_with(|map, head, _| {
13971                (
13972                    movement::previous_word_start(map, head),
13973                    SelectionGoal::None,
13974                )
13975            });
13976        })
13977    }
13978
13979    pub fn move_to_previous_subword_start(
13980        &mut self,
13981        _: &MoveToPreviousSubwordStart,
13982        window: &mut Window,
13983        cx: &mut Context<Self>,
13984    ) {
13985        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13986        self.change_selections(Default::default(), window, cx, |s| {
13987            s.move_cursors_with(|map, head, _| {
13988                (
13989                    movement::previous_subword_start(map, head),
13990                    SelectionGoal::None,
13991                )
13992            });
13993        })
13994    }
13995
13996    pub fn select_to_previous_word_start(
13997        &mut self,
13998        _: &SelectToPreviousWordStart,
13999        window: &mut Window,
14000        cx: &mut Context<Self>,
14001    ) {
14002        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14003        self.change_selections(Default::default(), window, cx, |s| {
14004            s.move_heads_with(|map, head, _| {
14005                (
14006                    movement::previous_word_start(map, head),
14007                    SelectionGoal::None,
14008                )
14009            });
14010        })
14011    }
14012
14013    pub fn select_to_previous_subword_start(
14014        &mut self,
14015        _: &SelectToPreviousSubwordStart,
14016        window: &mut Window,
14017        cx: &mut Context<Self>,
14018    ) {
14019        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14020        self.change_selections(Default::default(), window, cx, |s| {
14021            s.move_heads_with(|map, head, _| {
14022                (
14023                    movement::previous_subword_start(map, head),
14024                    SelectionGoal::None,
14025                )
14026            });
14027        })
14028    }
14029
14030    pub fn delete_to_previous_word_start(
14031        &mut self,
14032        action: &DeleteToPreviousWordStart,
14033        window: &mut Window,
14034        cx: &mut Context<Self>,
14035    ) {
14036        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14037        self.transact(window, cx, |this, window, cx| {
14038            this.select_autoclose_pair(window, cx);
14039            this.change_selections(Default::default(), window, cx, |s| {
14040                s.move_with(|map, selection| {
14041                    if selection.is_empty() {
14042                        let mut cursor = if action.ignore_newlines {
14043                            movement::previous_word_start(map, selection.head())
14044                        } else {
14045                            movement::previous_word_start_or_newline(map, selection.head())
14046                        };
14047                        cursor = movement::adjust_greedy_deletion(
14048                            map,
14049                            selection.head(),
14050                            cursor,
14051                            action.ignore_brackets,
14052                        );
14053                        selection.set_head(cursor, SelectionGoal::None);
14054                    }
14055                });
14056            });
14057            this.insert("", window, cx);
14058        });
14059    }
14060
14061    pub fn delete_to_previous_subword_start(
14062        &mut self,
14063        _: &DeleteToPreviousSubwordStart,
14064        window: &mut Window,
14065        cx: &mut Context<Self>,
14066    ) {
14067        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14068        self.transact(window, cx, |this, window, cx| {
14069            this.select_autoclose_pair(window, cx);
14070            this.change_selections(Default::default(), window, cx, |s| {
14071                s.move_with(|map, selection| {
14072                    if selection.is_empty() {
14073                        let mut cursor = movement::previous_subword_start(map, selection.head());
14074                        cursor =
14075                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14076                        selection.set_head(cursor, SelectionGoal::None);
14077                    }
14078                });
14079            });
14080            this.insert("", window, cx);
14081        });
14082    }
14083
14084    pub fn move_to_next_word_end(
14085        &mut self,
14086        _: &MoveToNextWordEnd,
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_cursors_with(|map, head, _| {
14093                (movement::next_word_end(map, head), SelectionGoal::None)
14094            });
14095        })
14096    }
14097
14098    pub fn move_to_next_subword_end(
14099        &mut self,
14100        _: &MoveToNextSubwordEnd,
14101        window: &mut Window,
14102        cx: &mut Context<Self>,
14103    ) {
14104        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14105        self.change_selections(Default::default(), window, cx, |s| {
14106            s.move_cursors_with(|map, head, _| {
14107                (movement::next_subword_end(map, head), SelectionGoal::None)
14108            });
14109        })
14110    }
14111
14112    pub fn select_to_next_word_end(
14113        &mut self,
14114        _: &SelectToNextWordEnd,
14115        window: &mut Window,
14116        cx: &mut Context<Self>,
14117    ) {
14118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14119        self.change_selections(Default::default(), window, cx, |s| {
14120            s.move_heads_with(|map, head, _| {
14121                (movement::next_word_end(map, head), SelectionGoal::None)
14122            });
14123        })
14124    }
14125
14126    pub fn select_to_next_subword_end(
14127        &mut self,
14128        _: &SelectToNextSubwordEnd,
14129        window: &mut Window,
14130        cx: &mut Context<Self>,
14131    ) {
14132        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14133        self.change_selections(Default::default(), window, cx, |s| {
14134            s.move_heads_with(|map, head, _| {
14135                (movement::next_subword_end(map, head), SelectionGoal::None)
14136            });
14137        })
14138    }
14139
14140    pub fn delete_to_next_word_end(
14141        &mut self,
14142        action: &DeleteToNextWordEnd,
14143        window: &mut Window,
14144        cx: &mut Context<Self>,
14145    ) {
14146        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14147        self.transact(window, cx, |this, window, cx| {
14148            this.change_selections(Default::default(), window, cx, |s| {
14149                s.move_with(|map, selection| {
14150                    if selection.is_empty() {
14151                        let mut cursor = if action.ignore_newlines {
14152                            movement::next_word_end(map, selection.head())
14153                        } else {
14154                            movement::next_word_end_or_newline(map, selection.head())
14155                        };
14156                        cursor = movement::adjust_greedy_deletion(
14157                            map,
14158                            selection.head(),
14159                            cursor,
14160                            action.ignore_brackets,
14161                        );
14162                        selection.set_head(cursor, SelectionGoal::None);
14163                    }
14164                });
14165            });
14166            this.insert("", window, cx);
14167        });
14168    }
14169
14170    pub fn delete_to_next_subword_end(
14171        &mut self,
14172        _: &DeleteToNextSubwordEnd,
14173        window: &mut Window,
14174        cx: &mut Context<Self>,
14175    ) {
14176        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14177        self.transact(window, cx, |this, window, cx| {
14178            this.change_selections(Default::default(), window, cx, |s| {
14179                s.move_with(|map, selection| {
14180                    if selection.is_empty() {
14181                        let mut cursor = movement::next_subword_end(map, selection.head());
14182                        cursor =
14183                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14184                        selection.set_head(cursor, SelectionGoal::None);
14185                    }
14186                });
14187            });
14188            this.insert("", window, cx);
14189        });
14190    }
14191
14192    pub fn move_to_beginning_of_line(
14193        &mut self,
14194        action: &MoveToBeginningOfLine,
14195        window: &mut Window,
14196        cx: &mut Context<Self>,
14197    ) {
14198        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14199        self.change_selections(Default::default(), window, cx, |s| {
14200            s.move_cursors_with(|map, head, _| {
14201                (
14202                    movement::indented_line_beginning(
14203                        map,
14204                        head,
14205                        action.stop_at_soft_wraps,
14206                        action.stop_at_indent,
14207                    ),
14208                    SelectionGoal::None,
14209                )
14210            });
14211        })
14212    }
14213
14214    pub fn select_to_beginning_of_line(
14215        &mut self,
14216        action: &SelectToBeginningOfLine,
14217        window: &mut Window,
14218        cx: &mut Context<Self>,
14219    ) {
14220        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14221        self.change_selections(Default::default(), window, cx, |s| {
14222            s.move_heads_with(|map, head, _| {
14223                (
14224                    movement::indented_line_beginning(
14225                        map,
14226                        head,
14227                        action.stop_at_soft_wraps,
14228                        action.stop_at_indent,
14229                    ),
14230                    SelectionGoal::None,
14231                )
14232            });
14233        });
14234    }
14235
14236    pub fn delete_to_beginning_of_line(
14237        &mut self,
14238        action: &DeleteToBeginningOfLine,
14239        window: &mut Window,
14240        cx: &mut Context<Self>,
14241    ) {
14242        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14243        self.transact(window, cx, |this, window, cx| {
14244            this.change_selections(Default::default(), window, cx, |s| {
14245                s.move_with(|_, selection| {
14246                    selection.reversed = true;
14247                });
14248            });
14249
14250            this.select_to_beginning_of_line(
14251                &SelectToBeginningOfLine {
14252                    stop_at_soft_wraps: false,
14253                    stop_at_indent: action.stop_at_indent,
14254                },
14255                window,
14256                cx,
14257            );
14258            this.backspace(&Backspace, window, cx);
14259        });
14260    }
14261
14262    pub fn move_to_end_of_line(
14263        &mut self,
14264        action: &MoveToEndOfLine,
14265        window: &mut Window,
14266        cx: &mut Context<Self>,
14267    ) {
14268        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14269        self.change_selections(Default::default(), window, cx, |s| {
14270            s.move_cursors_with(|map, head, _| {
14271                (
14272                    movement::line_end(map, head, action.stop_at_soft_wraps),
14273                    SelectionGoal::None,
14274                )
14275            });
14276        })
14277    }
14278
14279    pub fn select_to_end_of_line(
14280        &mut self,
14281        action: &SelectToEndOfLine,
14282        window: &mut Window,
14283        cx: &mut Context<Self>,
14284    ) {
14285        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14286        self.change_selections(Default::default(), window, cx, |s| {
14287            s.move_heads_with(|map, head, _| {
14288                (
14289                    movement::line_end(map, head, action.stop_at_soft_wraps),
14290                    SelectionGoal::None,
14291                )
14292            });
14293        })
14294    }
14295
14296    pub fn delete_to_end_of_line(
14297        &mut self,
14298        _: &DeleteToEndOfLine,
14299        window: &mut Window,
14300        cx: &mut Context<Self>,
14301    ) {
14302        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14303        self.transact(window, cx, |this, window, cx| {
14304            this.select_to_end_of_line(
14305                &SelectToEndOfLine {
14306                    stop_at_soft_wraps: false,
14307                },
14308                window,
14309                cx,
14310            );
14311            this.delete(&Delete, window, cx);
14312        });
14313    }
14314
14315    pub fn cut_to_end_of_line(
14316        &mut self,
14317        action: &CutToEndOfLine,
14318        window: &mut Window,
14319        cx: &mut Context<Self>,
14320    ) {
14321        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14322        self.transact(window, cx, |this, window, cx| {
14323            this.select_to_end_of_line(
14324                &SelectToEndOfLine {
14325                    stop_at_soft_wraps: false,
14326                },
14327                window,
14328                cx,
14329            );
14330            if !action.stop_at_newlines {
14331                this.change_selections(Default::default(), window, cx, |s| {
14332                    s.move_with(|_, sel| {
14333                        if sel.is_empty() {
14334                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14335                        }
14336                    });
14337                });
14338            }
14339            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14340            let item = this.cut_common(false, window, cx);
14341            cx.write_to_clipboard(item);
14342        });
14343    }
14344
14345    pub fn move_to_start_of_paragraph(
14346        &mut self,
14347        _: &MoveToStartOfParagraph,
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_with(|map, selection| {
14358                selection.collapse_to(
14359                    movement::start_of_paragraph(map, selection.head(), 1),
14360                    SelectionGoal::None,
14361                )
14362            });
14363        })
14364    }
14365
14366    pub fn move_to_end_of_paragraph(
14367        &mut self,
14368        _: &MoveToEndOfParagraph,
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_with(|map, selection| {
14379                selection.collapse_to(
14380                    movement::end_of_paragraph(map, selection.head(), 1),
14381                    SelectionGoal::None,
14382                )
14383            });
14384        })
14385    }
14386
14387    pub fn select_to_start_of_paragraph(
14388        &mut self,
14389        _: &SelectToStartOfParagraph,
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_heads_with(|map, head, _| {
14400                (
14401                    movement::start_of_paragraph(map, head, 1),
14402                    SelectionGoal::None,
14403                )
14404            });
14405        })
14406    }
14407
14408    pub fn select_to_end_of_paragraph(
14409        &mut self,
14410        _: &SelectToEndOfParagraph,
14411        window: &mut Window,
14412        cx: &mut Context<Self>,
14413    ) {
14414        if matches!(self.mode, EditorMode::SingleLine) {
14415            cx.propagate();
14416            return;
14417        }
14418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14419        self.change_selections(Default::default(), window, cx, |s| {
14420            s.move_heads_with(|map, head, _| {
14421                (
14422                    movement::end_of_paragraph(map, head, 1),
14423                    SelectionGoal::None,
14424                )
14425            });
14426        })
14427    }
14428
14429    pub fn move_to_start_of_excerpt(
14430        &mut self,
14431        _: &MoveToStartOfExcerpt,
14432        window: &mut Window,
14433        cx: &mut Context<Self>,
14434    ) {
14435        if matches!(self.mode, EditorMode::SingleLine) {
14436            cx.propagate();
14437            return;
14438        }
14439        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14440        self.change_selections(Default::default(), window, cx, |s| {
14441            s.move_with(|map, selection| {
14442                selection.collapse_to(
14443                    movement::start_of_excerpt(
14444                        map,
14445                        selection.head(),
14446                        workspace::searchable::Direction::Prev,
14447                    ),
14448                    SelectionGoal::None,
14449                )
14450            });
14451        })
14452    }
14453
14454    pub fn move_to_start_of_next_excerpt(
14455        &mut self,
14456        _: &MoveToStartOfNextExcerpt,
14457        window: &mut Window,
14458        cx: &mut Context<Self>,
14459    ) {
14460        if matches!(self.mode, EditorMode::SingleLine) {
14461            cx.propagate();
14462            return;
14463        }
14464
14465        self.change_selections(Default::default(), window, cx, |s| {
14466            s.move_with(|map, selection| {
14467                selection.collapse_to(
14468                    movement::start_of_excerpt(
14469                        map,
14470                        selection.head(),
14471                        workspace::searchable::Direction::Next,
14472                    ),
14473                    SelectionGoal::None,
14474                )
14475            });
14476        })
14477    }
14478
14479    pub fn move_to_end_of_excerpt(
14480        &mut self,
14481        _: &MoveToEndOfExcerpt,
14482        window: &mut Window,
14483        cx: &mut Context<Self>,
14484    ) {
14485        if matches!(self.mode, EditorMode::SingleLine) {
14486            cx.propagate();
14487            return;
14488        }
14489        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14490        self.change_selections(Default::default(), window, cx, |s| {
14491            s.move_with(|map, selection| {
14492                selection.collapse_to(
14493                    movement::end_of_excerpt(
14494                        map,
14495                        selection.head(),
14496                        workspace::searchable::Direction::Next,
14497                    ),
14498                    SelectionGoal::None,
14499                )
14500            });
14501        })
14502    }
14503
14504    pub fn move_to_end_of_previous_excerpt(
14505        &mut self,
14506        _: &MoveToEndOfPreviousExcerpt,
14507        window: &mut Window,
14508        cx: &mut Context<Self>,
14509    ) {
14510        if matches!(self.mode, EditorMode::SingleLine) {
14511            cx.propagate();
14512            return;
14513        }
14514        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14515        self.change_selections(Default::default(), window, cx, |s| {
14516            s.move_with(|map, selection| {
14517                selection.collapse_to(
14518                    movement::end_of_excerpt(
14519                        map,
14520                        selection.head(),
14521                        workspace::searchable::Direction::Prev,
14522                    ),
14523                    SelectionGoal::None,
14524                )
14525            });
14526        })
14527    }
14528
14529    pub fn select_to_start_of_excerpt(
14530        &mut self,
14531        _: &SelectToStartOfExcerpt,
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::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14544                    SelectionGoal::None,
14545                )
14546            });
14547        })
14548    }
14549
14550    pub fn select_to_start_of_next_excerpt(
14551        &mut self,
14552        _: &SelectToStartOfNextExcerpt,
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::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14565                    SelectionGoal::None,
14566                )
14567            });
14568        })
14569    }
14570
14571    pub fn select_to_end_of_excerpt(
14572        &mut self,
14573        _: &SelectToEndOfExcerpt,
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.move_heads_with(|map, head, _| {
14584                (
14585                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14586                    SelectionGoal::None,
14587                )
14588            });
14589        })
14590    }
14591
14592    pub fn select_to_end_of_previous_excerpt(
14593        &mut self,
14594        _: &SelectToEndOfPreviousExcerpt,
14595        window: &mut Window,
14596        cx: &mut Context<Self>,
14597    ) {
14598        if matches!(self.mode, EditorMode::SingleLine) {
14599            cx.propagate();
14600            return;
14601        }
14602        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14603        self.change_selections(Default::default(), window, cx, |s| {
14604            s.move_heads_with(|map, head, _| {
14605                (
14606                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14607                    SelectionGoal::None,
14608                )
14609            });
14610        })
14611    }
14612
14613    pub fn move_to_beginning(
14614        &mut self,
14615        _: &MoveToBeginning,
14616        window: &mut Window,
14617        cx: &mut Context<Self>,
14618    ) {
14619        if matches!(self.mode, EditorMode::SingleLine) {
14620            cx.propagate();
14621            return;
14622        }
14623        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14624        self.change_selections(Default::default(), window, cx, |s| {
14625            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14626        });
14627    }
14628
14629    pub fn select_to_beginning(
14630        &mut self,
14631        _: &SelectToBeginning,
14632        window: &mut Window,
14633        cx: &mut Context<Self>,
14634    ) {
14635        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14636        selection.set_head(Point::zero(), SelectionGoal::None);
14637        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14638        self.change_selections(Default::default(), window, cx, |s| {
14639            s.select(vec![selection]);
14640        });
14641    }
14642
14643    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14644        if matches!(self.mode, EditorMode::SingleLine) {
14645            cx.propagate();
14646            return;
14647        }
14648        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14649        let cursor = self.buffer.read(cx).read(cx).len();
14650        self.change_selections(Default::default(), window, cx, |s| {
14651            s.select_ranges(vec![cursor..cursor])
14652        });
14653    }
14654
14655    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14656        self.nav_history = nav_history;
14657    }
14658
14659    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14660        self.nav_history.as_ref()
14661    }
14662
14663    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14664        self.push_to_nav_history(
14665            self.selections.newest_anchor().head(),
14666            None,
14667            false,
14668            true,
14669            cx,
14670        );
14671    }
14672
14673    fn push_to_nav_history(
14674        &mut self,
14675        cursor_anchor: Anchor,
14676        new_position: Option<Point>,
14677        is_deactivate: bool,
14678        always: bool,
14679        cx: &mut Context<Self>,
14680    ) {
14681        if let Some(nav_history) = self.nav_history.as_mut() {
14682            let buffer = self.buffer.read(cx).read(cx);
14683            let cursor_position = cursor_anchor.to_point(&buffer);
14684            let scroll_state = self.scroll_manager.anchor();
14685            let scroll_top_row = scroll_state.top_row(&buffer);
14686            drop(buffer);
14687
14688            if let Some(new_position) = new_position {
14689                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14690                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14691                    return;
14692                }
14693            }
14694
14695            nav_history.push(
14696                Some(NavigationData {
14697                    cursor_anchor,
14698                    cursor_position,
14699                    scroll_anchor: scroll_state,
14700                    scroll_top_row,
14701                }),
14702                cx,
14703            );
14704            cx.emit(EditorEvent::PushedToNavHistory {
14705                anchor: cursor_anchor,
14706                is_deactivate,
14707            })
14708        }
14709    }
14710
14711    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14712        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14713        let buffer = self.buffer.read(cx).snapshot(cx);
14714        let mut selection = self
14715            .selections
14716            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14717        selection.set_head(buffer.len(), SelectionGoal::None);
14718        self.change_selections(Default::default(), window, cx, |s| {
14719            s.select(vec![selection]);
14720        });
14721    }
14722
14723    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14724        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14725        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14726            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14727        });
14728    }
14729
14730    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14732        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14733        let mut selections = self.selections.all::<Point>(&display_map);
14734        let max_point = display_map.buffer_snapshot().max_point();
14735        for selection in &mut selections {
14736            let rows = selection.spanned_rows(true, &display_map);
14737            selection.start = Point::new(rows.start.0, 0);
14738            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14739            selection.reversed = false;
14740        }
14741        self.change_selections(Default::default(), window, cx, |s| {
14742            s.select(selections);
14743        });
14744    }
14745
14746    pub fn split_selection_into_lines(
14747        &mut self,
14748        action: &SplitSelectionIntoLines,
14749        window: &mut Window,
14750        cx: &mut Context<Self>,
14751    ) {
14752        let selections = self
14753            .selections
14754            .all::<Point>(&self.display_snapshot(cx))
14755            .into_iter()
14756            .map(|selection| selection.start..selection.end)
14757            .collect::<Vec<_>>();
14758        self.unfold_ranges(&selections, true, true, cx);
14759
14760        let mut new_selection_ranges = Vec::new();
14761        {
14762            let buffer = self.buffer.read(cx).read(cx);
14763            for selection in selections {
14764                for row in selection.start.row..selection.end.row {
14765                    let line_start = Point::new(row, 0);
14766                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14767
14768                    if action.keep_selections {
14769                        // Keep the selection range for each line
14770                        let selection_start = if row == selection.start.row {
14771                            selection.start
14772                        } else {
14773                            line_start
14774                        };
14775                        new_selection_ranges.push(selection_start..line_end);
14776                    } else {
14777                        // Collapse to cursor at end of line
14778                        new_selection_ranges.push(line_end..line_end);
14779                    }
14780                }
14781
14782                let is_multiline_selection = selection.start.row != selection.end.row;
14783                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14784                // so this action feels more ergonomic when paired with other selection operations
14785                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14786                if !should_skip_last {
14787                    if action.keep_selections {
14788                        if is_multiline_selection {
14789                            let line_start = Point::new(selection.end.row, 0);
14790                            new_selection_ranges.push(line_start..selection.end);
14791                        } else {
14792                            new_selection_ranges.push(selection.start..selection.end);
14793                        }
14794                    } else {
14795                        new_selection_ranges.push(selection.end..selection.end);
14796                    }
14797                }
14798            }
14799        }
14800        self.change_selections(Default::default(), window, cx, |s| {
14801            s.select_ranges(new_selection_ranges);
14802        });
14803    }
14804
14805    pub fn add_selection_above(
14806        &mut self,
14807        action: &AddSelectionAbove,
14808        window: &mut Window,
14809        cx: &mut Context<Self>,
14810    ) {
14811        self.add_selection(true, action.skip_soft_wrap, window, cx);
14812    }
14813
14814    pub fn add_selection_below(
14815        &mut self,
14816        action: &AddSelectionBelow,
14817        window: &mut Window,
14818        cx: &mut Context<Self>,
14819    ) {
14820        self.add_selection(false, action.skip_soft_wrap, window, cx);
14821    }
14822
14823    fn add_selection(
14824        &mut self,
14825        above: bool,
14826        skip_soft_wrap: bool,
14827        window: &mut Window,
14828        cx: &mut Context<Self>,
14829    ) {
14830        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14831
14832        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14833        let all_selections = self.selections.all::<Point>(&display_map);
14834        let text_layout_details = self.text_layout_details(window);
14835
14836        let (mut columnar_selections, new_selections_to_columnarize) = {
14837            if let Some(state) = self.add_selections_state.as_ref() {
14838                let columnar_selection_ids: HashSet<_> = state
14839                    .groups
14840                    .iter()
14841                    .flat_map(|group| group.stack.iter())
14842                    .copied()
14843                    .collect();
14844
14845                all_selections
14846                    .into_iter()
14847                    .partition(|s| columnar_selection_ids.contains(&s.id))
14848            } else {
14849                (Vec::new(), all_selections)
14850            }
14851        };
14852
14853        let mut state = self
14854            .add_selections_state
14855            .take()
14856            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14857
14858        for selection in new_selections_to_columnarize {
14859            let range = selection.display_range(&display_map).sorted();
14860            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14861            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14862            let positions = start_x.min(end_x)..start_x.max(end_x);
14863            let mut stack = Vec::new();
14864            for row in range.start.row().0..=range.end.row().0 {
14865                if let Some(selection) = self.selections.build_columnar_selection(
14866                    &display_map,
14867                    DisplayRow(row),
14868                    &positions,
14869                    selection.reversed,
14870                    &text_layout_details,
14871                ) {
14872                    stack.push(selection.id);
14873                    columnar_selections.push(selection);
14874                }
14875            }
14876            if !stack.is_empty() {
14877                if above {
14878                    stack.reverse();
14879                }
14880                state.groups.push(AddSelectionsGroup { above, stack });
14881            }
14882        }
14883
14884        let mut final_selections = Vec::new();
14885        let end_row = if above {
14886            DisplayRow(0)
14887        } else {
14888            display_map.max_point().row()
14889        };
14890
14891        let mut last_added_item_per_group = HashMap::default();
14892        for group in state.groups.iter_mut() {
14893            if let Some(last_id) = group.stack.last() {
14894                last_added_item_per_group.insert(*last_id, group);
14895            }
14896        }
14897
14898        for selection in columnar_selections {
14899            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14900                if above == group.above {
14901                    let range = selection.display_range(&display_map).sorted();
14902                    debug_assert_eq!(range.start.row(), range.end.row());
14903                    let mut row = range.start.row();
14904                    let positions =
14905                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14906                            Pixels::from(start)..Pixels::from(end)
14907                        } else {
14908                            let start_x =
14909                                display_map.x_for_display_point(range.start, &text_layout_details);
14910                            let end_x =
14911                                display_map.x_for_display_point(range.end, &text_layout_details);
14912                            start_x.min(end_x)..start_x.max(end_x)
14913                        };
14914
14915                    let mut maybe_new_selection = None;
14916                    let direction = if above { -1 } else { 1 };
14917
14918                    while row != end_row {
14919                        if skip_soft_wrap {
14920                            row = display_map
14921                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14922                                .row();
14923                        } else if above {
14924                            row.0 -= 1;
14925                        } else {
14926                            row.0 += 1;
14927                        }
14928
14929                        if let Some(new_selection) = self.selections.build_columnar_selection(
14930                            &display_map,
14931                            row,
14932                            &positions,
14933                            selection.reversed,
14934                            &text_layout_details,
14935                        ) {
14936                            maybe_new_selection = Some(new_selection);
14937                            break;
14938                        }
14939                    }
14940
14941                    if let Some(new_selection) = maybe_new_selection {
14942                        group.stack.push(new_selection.id);
14943                        if above {
14944                            final_selections.push(new_selection);
14945                            final_selections.push(selection);
14946                        } else {
14947                            final_selections.push(selection);
14948                            final_selections.push(new_selection);
14949                        }
14950                    } else {
14951                        final_selections.push(selection);
14952                    }
14953                } else {
14954                    group.stack.pop();
14955                }
14956            } else {
14957                final_selections.push(selection);
14958            }
14959        }
14960
14961        self.change_selections(Default::default(), window, cx, |s| {
14962            s.select(final_selections);
14963        });
14964
14965        let final_selection_ids: HashSet<_> = self
14966            .selections
14967            .all::<Point>(&display_map)
14968            .iter()
14969            .map(|s| s.id)
14970            .collect();
14971        state.groups.retain_mut(|group| {
14972            // selections might get merged above so we remove invalid items from stacks
14973            group.stack.retain(|id| final_selection_ids.contains(id));
14974
14975            // single selection in stack can be treated as initial state
14976            group.stack.len() > 1
14977        });
14978
14979        if !state.groups.is_empty() {
14980            self.add_selections_state = Some(state);
14981        }
14982    }
14983
14984    pub fn insert_snippet_at_selections(
14985        &mut self,
14986        action: &InsertSnippet,
14987        window: &mut Window,
14988        cx: &mut Context<Self>,
14989    ) {
14990        self.try_insert_snippet_at_selections(action, window, cx)
14991            .log_err();
14992    }
14993
14994    fn try_insert_snippet_at_selections(
14995        &mut self,
14996        action: &InsertSnippet,
14997        window: &mut Window,
14998        cx: &mut Context<Self>,
14999    ) -> Result<()> {
15000        let insertion_ranges = self
15001            .selections
15002            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15003            .into_iter()
15004            .map(|selection| selection.range())
15005            .collect_vec();
15006
15007        let snippet = if let Some(snippet_body) = &action.snippet {
15008            if action.language.is_none() && action.name.is_none() {
15009                Snippet::parse(snippet_body)?
15010            } else {
15011                bail!("`snippet` is mutually exclusive with `language` and `name`")
15012            }
15013        } else if let Some(name) = &action.name {
15014            let project = self.project().context("no project")?;
15015            let snippet_store = project.read(cx).snippets().read(cx);
15016            let snippet = snippet_store
15017                .snippets_for(action.language.clone(), cx)
15018                .into_iter()
15019                .find(|snippet| snippet.name == *name)
15020                .context("snippet not found")?;
15021            Snippet::parse(&snippet.body)?
15022        } else {
15023            // todo(andrew): open modal to select snippet
15024            bail!("`name` or `snippet` is required")
15025        };
15026
15027        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15028    }
15029
15030    fn select_match_ranges(
15031        &mut self,
15032        range: Range<MultiBufferOffset>,
15033        reversed: bool,
15034        replace_newest: bool,
15035        auto_scroll: Option<Autoscroll>,
15036        window: &mut Window,
15037        cx: &mut Context<Editor>,
15038    ) {
15039        self.unfold_ranges(
15040            std::slice::from_ref(&range),
15041            false,
15042            auto_scroll.is_some(),
15043            cx,
15044        );
15045        let effects = if let Some(scroll) = auto_scroll {
15046            SelectionEffects::scroll(scroll)
15047        } else {
15048            SelectionEffects::no_scroll()
15049        };
15050        self.change_selections(effects, window, cx, |s| {
15051            if replace_newest {
15052                s.delete(s.newest_anchor().id);
15053            }
15054            if reversed {
15055                s.insert_range(range.end..range.start);
15056            } else {
15057                s.insert_range(range);
15058            }
15059        });
15060    }
15061
15062    pub fn select_next_match_internal(
15063        &mut self,
15064        display_map: &DisplaySnapshot,
15065        replace_newest: bool,
15066        autoscroll: Option<Autoscroll>,
15067        window: &mut Window,
15068        cx: &mut Context<Self>,
15069    ) -> Result<()> {
15070        let buffer = display_map.buffer_snapshot();
15071        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15072        if let Some(mut select_next_state) = self.select_next_state.take() {
15073            let query = &select_next_state.query;
15074            if !select_next_state.done {
15075                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15076                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15077                let mut next_selected_range = None;
15078
15079                let bytes_after_last_selection =
15080                    buffer.bytes_in_range(last_selection.end..buffer.len());
15081                let bytes_before_first_selection =
15082                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15083                let query_matches = query
15084                    .stream_find_iter(bytes_after_last_selection)
15085                    .map(|result| (last_selection.end, result))
15086                    .chain(
15087                        query
15088                            .stream_find_iter(bytes_before_first_selection)
15089                            .map(|result| (MultiBufferOffset(0), result)),
15090                    );
15091
15092                for (start_offset, query_match) in query_matches {
15093                    let query_match = query_match.unwrap(); // can only fail due to I/O
15094                    let offset_range =
15095                        start_offset + query_match.start()..start_offset + query_match.end();
15096
15097                    if !select_next_state.wordwise
15098                        || (!buffer.is_inside_word(offset_range.start, None)
15099                            && !buffer.is_inside_word(offset_range.end, None))
15100                    {
15101                        let idx = selections
15102                            .partition_point(|selection| selection.end <= offset_range.start);
15103                        let overlaps = selections
15104                            .get(idx)
15105                            .map_or(false, |selection| selection.start < offset_range.end);
15106
15107                        if !overlaps {
15108                            next_selected_range = Some(offset_range);
15109                            break;
15110                        }
15111                    }
15112                }
15113
15114                if let Some(next_selected_range) = next_selected_range {
15115                    self.select_match_ranges(
15116                        next_selected_range,
15117                        last_selection.reversed,
15118                        replace_newest,
15119                        autoscroll,
15120                        window,
15121                        cx,
15122                    );
15123                } else {
15124                    select_next_state.done = true;
15125                }
15126            }
15127
15128            self.select_next_state = Some(select_next_state);
15129        } else {
15130            let mut only_carets = true;
15131            let mut same_text_selected = true;
15132            let mut selected_text = None;
15133
15134            let mut selections_iter = selections.iter().peekable();
15135            while let Some(selection) = selections_iter.next() {
15136                if selection.start != selection.end {
15137                    only_carets = false;
15138                }
15139
15140                if same_text_selected {
15141                    if selected_text.is_none() {
15142                        selected_text =
15143                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15144                    }
15145
15146                    if let Some(next_selection) = selections_iter.peek() {
15147                        if next_selection.len() == selection.len() {
15148                            let next_selected_text = buffer
15149                                .text_for_range(next_selection.range())
15150                                .collect::<String>();
15151                            if Some(next_selected_text) != selected_text {
15152                                same_text_selected = false;
15153                                selected_text = None;
15154                            }
15155                        } else {
15156                            same_text_selected = false;
15157                            selected_text = None;
15158                        }
15159                    }
15160                }
15161            }
15162
15163            if only_carets {
15164                for selection in &mut selections {
15165                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15166                    selection.start = word_range.start;
15167                    selection.end = word_range.end;
15168                    selection.goal = SelectionGoal::None;
15169                    selection.reversed = false;
15170                    self.select_match_ranges(
15171                        selection.start..selection.end,
15172                        selection.reversed,
15173                        replace_newest,
15174                        autoscroll,
15175                        window,
15176                        cx,
15177                    );
15178                }
15179
15180                if selections.len() == 1 {
15181                    let selection = selections
15182                        .last()
15183                        .expect("ensured that there's only one selection");
15184                    let query = buffer
15185                        .text_for_range(selection.start..selection.end)
15186                        .collect::<String>();
15187                    let is_empty = query.is_empty();
15188                    let select_state = SelectNextState {
15189                        query: self.build_query(&[query], cx)?,
15190                        wordwise: true,
15191                        done: is_empty,
15192                    };
15193                    self.select_next_state = Some(select_state);
15194                } else {
15195                    self.select_next_state = None;
15196                }
15197            } else if let Some(selected_text) = selected_text {
15198                self.select_next_state = Some(SelectNextState {
15199                    query: self.build_query(&[selected_text], cx)?,
15200                    wordwise: false,
15201                    done: false,
15202                });
15203                self.select_next_match_internal(
15204                    display_map,
15205                    replace_newest,
15206                    autoscroll,
15207                    window,
15208                    cx,
15209                )?;
15210            }
15211        }
15212        Ok(())
15213    }
15214
15215    pub fn select_all_matches(
15216        &mut self,
15217        _action: &SelectAllMatches,
15218        window: &mut Window,
15219        cx: &mut Context<Self>,
15220    ) -> Result<()> {
15221        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15222
15223        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15224
15225        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15226        let Some(select_next_state) = self.select_next_state.as_mut() else {
15227            return Ok(());
15228        };
15229        if select_next_state.done {
15230            return Ok(());
15231        }
15232
15233        let mut new_selections = Vec::new();
15234
15235        let reversed = self
15236            .selections
15237            .oldest::<MultiBufferOffset>(&display_map)
15238            .reversed;
15239        let buffer = display_map.buffer_snapshot();
15240        let query_matches = select_next_state
15241            .query
15242            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15243
15244        for query_match in query_matches.into_iter() {
15245            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15246            let offset_range = if reversed {
15247                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15248            } else {
15249                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15250            };
15251
15252            if !select_next_state.wordwise
15253                || (!buffer.is_inside_word(offset_range.start, None)
15254                    && !buffer.is_inside_word(offset_range.end, None))
15255            {
15256                new_selections.push(offset_range.start..offset_range.end);
15257            }
15258        }
15259
15260        select_next_state.done = true;
15261
15262        if new_selections.is_empty() {
15263            log::error!("bug: new_selections is empty in select_all_matches");
15264            return Ok(());
15265        }
15266
15267        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15268        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15269            selections.select_ranges(new_selections)
15270        });
15271
15272        Ok(())
15273    }
15274
15275    pub fn select_next(
15276        &mut self,
15277        action: &SelectNext,
15278        window: &mut Window,
15279        cx: &mut Context<Self>,
15280    ) -> Result<()> {
15281        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15282        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15283        self.select_next_match_internal(
15284            &display_map,
15285            action.replace_newest,
15286            Some(Autoscroll::newest()),
15287            window,
15288            cx,
15289        )?;
15290        Ok(())
15291    }
15292
15293    pub fn select_previous(
15294        &mut self,
15295        action: &SelectPrevious,
15296        window: &mut Window,
15297        cx: &mut Context<Self>,
15298    ) -> Result<()> {
15299        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15300        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15301        let buffer = display_map.buffer_snapshot();
15302        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15303        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15304            let query = &select_prev_state.query;
15305            if !select_prev_state.done {
15306                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15307                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15308                let mut next_selected_range = None;
15309                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15310                let bytes_before_last_selection =
15311                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15312                let bytes_after_first_selection =
15313                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15314                let query_matches = query
15315                    .stream_find_iter(bytes_before_last_selection)
15316                    .map(|result| (last_selection.start, result))
15317                    .chain(
15318                        query
15319                            .stream_find_iter(bytes_after_first_selection)
15320                            .map(|result| (buffer.len(), result)),
15321                    );
15322                for (end_offset, query_match) in query_matches {
15323                    let query_match = query_match.unwrap(); // can only fail due to I/O
15324                    let offset_range =
15325                        end_offset - query_match.end()..end_offset - query_match.start();
15326
15327                    if !select_prev_state.wordwise
15328                        || (!buffer.is_inside_word(offset_range.start, None)
15329                            && !buffer.is_inside_word(offset_range.end, None))
15330                    {
15331                        next_selected_range = Some(offset_range);
15332                        break;
15333                    }
15334                }
15335
15336                if let Some(next_selected_range) = next_selected_range {
15337                    self.select_match_ranges(
15338                        next_selected_range,
15339                        last_selection.reversed,
15340                        action.replace_newest,
15341                        Some(Autoscroll::newest()),
15342                        window,
15343                        cx,
15344                    );
15345                } else {
15346                    select_prev_state.done = true;
15347                }
15348            }
15349
15350            self.select_prev_state = Some(select_prev_state);
15351        } else {
15352            let mut only_carets = true;
15353            let mut same_text_selected = true;
15354            let mut selected_text = None;
15355
15356            let mut selections_iter = selections.iter().peekable();
15357            while let Some(selection) = selections_iter.next() {
15358                if selection.start != selection.end {
15359                    only_carets = false;
15360                }
15361
15362                if same_text_selected {
15363                    if selected_text.is_none() {
15364                        selected_text =
15365                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15366                    }
15367
15368                    if let Some(next_selection) = selections_iter.peek() {
15369                        if next_selection.len() == selection.len() {
15370                            let next_selected_text = buffer
15371                                .text_for_range(next_selection.range())
15372                                .collect::<String>();
15373                            if Some(next_selected_text) != selected_text {
15374                                same_text_selected = false;
15375                                selected_text = None;
15376                            }
15377                        } else {
15378                            same_text_selected = false;
15379                            selected_text = None;
15380                        }
15381                    }
15382                }
15383            }
15384
15385            if only_carets {
15386                for selection in &mut selections {
15387                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15388                    selection.start = word_range.start;
15389                    selection.end = word_range.end;
15390                    selection.goal = SelectionGoal::None;
15391                    selection.reversed = false;
15392                    self.select_match_ranges(
15393                        selection.start..selection.end,
15394                        selection.reversed,
15395                        action.replace_newest,
15396                        Some(Autoscroll::newest()),
15397                        window,
15398                        cx,
15399                    );
15400                }
15401                if selections.len() == 1 {
15402                    let selection = selections
15403                        .last()
15404                        .expect("ensured that there's only one selection");
15405                    let query = buffer
15406                        .text_for_range(selection.start..selection.end)
15407                        .collect::<String>();
15408                    let is_empty = query.is_empty();
15409                    let select_state = SelectNextState {
15410                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15411                        wordwise: true,
15412                        done: is_empty,
15413                    };
15414                    self.select_prev_state = Some(select_state);
15415                } else {
15416                    self.select_prev_state = None;
15417                }
15418            } else if let Some(selected_text) = selected_text {
15419                self.select_prev_state = Some(SelectNextState {
15420                    query: self
15421                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15422                    wordwise: false,
15423                    done: false,
15424                });
15425                self.select_previous(action, window, cx)?;
15426            }
15427        }
15428        Ok(())
15429    }
15430
15431    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15432    /// setting the case sensitivity based on the global
15433    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15434    /// editor's settings.
15435    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15436    where
15437        I: IntoIterator<Item = P>,
15438        P: AsRef<[u8]>,
15439    {
15440        let case_sensitive = self
15441            .select_next_is_case_sensitive
15442            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15443
15444        let mut builder = AhoCorasickBuilder::new();
15445        builder.ascii_case_insensitive(!case_sensitive);
15446        builder.build(patterns)
15447    }
15448
15449    pub fn find_next_match(
15450        &mut self,
15451        _: &FindNextMatch,
15452        window: &mut Window,
15453        cx: &mut Context<Self>,
15454    ) -> Result<()> {
15455        let selections = self.selections.disjoint_anchors_arc();
15456        match selections.first() {
15457            Some(first) if selections.len() >= 2 => {
15458                self.change_selections(Default::default(), window, cx, |s| {
15459                    s.select_ranges([first.range()]);
15460                });
15461            }
15462            _ => self.select_next(
15463                &SelectNext {
15464                    replace_newest: true,
15465                },
15466                window,
15467                cx,
15468            )?,
15469        }
15470        Ok(())
15471    }
15472
15473    pub fn find_previous_match(
15474        &mut self,
15475        _: &FindPreviousMatch,
15476        window: &mut Window,
15477        cx: &mut Context<Self>,
15478    ) -> Result<()> {
15479        let selections = self.selections.disjoint_anchors_arc();
15480        match selections.last() {
15481            Some(last) if selections.len() >= 2 => {
15482                self.change_selections(Default::default(), window, cx, |s| {
15483                    s.select_ranges([last.range()]);
15484                });
15485            }
15486            _ => self.select_previous(
15487                &SelectPrevious {
15488                    replace_newest: true,
15489                },
15490                window,
15491                cx,
15492            )?,
15493        }
15494        Ok(())
15495    }
15496
15497    pub fn toggle_comments(
15498        &mut self,
15499        action: &ToggleComments,
15500        window: &mut Window,
15501        cx: &mut Context<Self>,
15502    ) {
15503        if self.read_only(cx) {
15504            return;
15505        }
15506        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15507        let text_layout_details = &self.text_layout_details(window);
15508        self.transact(window, cx, |this, window, cx| {
15509            let mut selections = this
15510                .selections
15511                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15512            let mut edits = Vec::new();
15513            let mut selection_edit_ranges = Vec::new();
15514            let mut last_toggled_row = None;
15515            let snapshot = this.buffer.read(cx).read(cx);
15516            let empty_str: Arc<str> = Arc::default();
15517            let mut suffixes_inserted = Vec::new();
15518            let ignore_indent = action.ignore_indent;
15519
15520            fn comment_prefix_range(
15521                snapshot: &MultiBufferSnapshot,
15522                row: MultiBufferRow,
15523                comment_prefix: &str,
15524                comment_prefix_whitespace: &str,
15525                ignore_indent: bool,
15526            ) -> Range<Point> {
15527                let indent_size = if ignore_indent {
15528                    0
15529                } else {
15530                    snapshot.indent_size_for_line(row).len
15531                };
15532
15533                let start = Point::new(row.0, indent_size);
15534
15535                let mut line_bytes = snapshot
15536                    .bytes_in_range(start..snapshot.max_point())
15537                    .flatten()
15538                    .copied();
15539
15540                // If this line currently begins with the line comment prefix, then record
15541                // the range containing the prefix.
15542                if line_bytes
15543                    .by_ref()
15544                    .take(comment_prefix.len())
15545                    .eq(comment_prefix.bytes())
15546                {
15547                    // Include any whitespace that matches the comment prefix.
15548                    let matching_whitespace_len = line_bytes
15549                        .zip(comment_prefix_whitespace.bytes())
15550                        .take_while(|(a, b)| a == b)
15551                        .count() as u32;
15552                    let end = Point::new(
15553                        start.row,
15554                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15555                    );
15556                    start..end
15557                } else {
15558                    start..start
15559                }
15560            }
15561
15562            fn comment_suffix_range(
15563                snapshot: &MultiBufferSnapshot,
15564                row: MultiBufferRow,
15565                comment_suffix: &str,
15566                comment_suffix_has_leading_space: bool,
15567            ) -> Range<Point> {
15568                let end = Point::new(row.0, snapshot.line_len(row));
15569                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15570
15571                let mut line_end_bytes = snapshot
15572                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15573                    .flatten()
15574                    .copied();
15575
15576                let leading_space_len = if suffix_start_column > 0
15577                    && line_end_bytes.next() == Some(b' ')
15578                    && comment_suffix_has_leading_space
15579                {
15580                    1
15581                } else {
15582                    0
15583                };
15584
15585                // If this line currently begins with the line comment prefix, then record
15586                // the range containing the prefix.
15587                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15588                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15589                    start..end
15590                } else {
15591                    end..end
15592                }
15593            }
15594
15595            // TODO: Handle selections that cross excerpts
15596            for selection in &mut selections {
15597                let start_column = snapshot
15598                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15599                    .len;
15600                let language = if let Some(language) =
15601                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15602                {
15603                    language
15604                } else {
15605                    continue;
15606                };
15607
15608                selection_edit_ranges.clear();
15609
15610                // If multiple selections contain a given row, avoid processing that
15611                // row more than once.
15612                let mut start_row = MultiBufferRow(selection.start.row);
15613                if last_toggled_row == Some(start_row) {
15614                    start_row = start_row.next_row();
15615                }
15616                let end_row =
15617                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15618                        MultiBufferRow(selection.end.row - 1)
15619                    } else {
15620                        MultiBufferRow(selection.end.row)
15621                    };
15622                last_toggled_row = Some(end_row);
15623
15624                if start_row > end_row {
15625                    continue;
15626                }
15627
15628                // If the language has line comments, toggle those.
15629                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15630
15631                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15632                if ignore_indent {
15633                    full_comment_prefixes = full_comment_prefixes
15634                        .into_iter()
15635                        .map(|s| Arc::from(s.trim_end()))
15636                        .collect();
15637                }
15638
15639                if !full_comment_prefixes.is_empty() {
15640                    let first_prefix = full_comment_prefixes
15641                        .first()
15642                        .expect("prefixes is non-empty");
15643                    let prefix_trimmed_lengths = full_comment_prefixes
15644                        .iter()
15645                        .map(|p| p.trim_end_matches(' ').len())
15646                        .collect::<SmallVec<[usize; 4]>>();
15647
15648                    let mut all_selection_lines_are_comments = true;
15649
15650                    for row in start_row.0..=end_row.0 {
15651                        let row = MultiBufferRow(row);
15652                        if start_row < end_row && snapshot.is_line_blank(row) {
15653                            continue;
15654                        }
15655
15656                        let prefix_range = full_comment_prefixes
15657                            .iter()
15658                            .zip(prefix_trimmed_lengths.iter().copied())
15659                            .map(|(prefix, trimmed_prefix_len)| {
15660                                comment_prefix_range(
15661                                    snapshot.deref(),
15662                                    row,
15663                                    &prefix[..trimmed_prefix_len],
15664                                    &prefix[trimmed_prefix_len..],
15665                                    ignore_indent,
15666                                )
15667                            })
15668                            .max_by_key(|range| range.end.column - range.start.column)
15669                            .expect("prefixes is non-empty");
15670
15671                        if prefix_range.is_empty() {
15672                            all_selection_lines_are_comments = false;
15673                        }
15674
15675                        selection_edit_ranges.push(prefix_range);
15676                    }
15677
15678                    if all_selection_lines_are_comments {
15679                        edits.extend(
15680                            selection_edit_ranges
15681                                .iter()
15682                                .cloned()
15683                                .map(|range| (range, empty_str.clone())),
15684                        );
15685                    } else {
15686                        let min_column = selection_edit_ranges
15687                            .iter()
15688                            .map(|range| range.start.column)
15689                            .min()
15690                            .unwrap_or(0);
15691                        edits.extend(selection_edit_ranges.iter().map(|range| {
15692                            let position = Point::new(range.start.row, min_column);
15693                            (position..position, first_prefix.clone())
15694                        }));
15695                    }
15696                } else if let Some(BlockCommentConfig {
15697                    start: full_comment_prefix,
15698                    end: comment_suffix,
15699                    ..
15700                }) = language.block_comment()
15701                {
15702                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15703                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15704                    let prefix_range = comment_prefix_range(
15705                        snapshot.deref(),
15706                        start_row,
15707                        comment_prefix,
15708                        comment_prefix_whitespace,
15709                        ignore_indent,
15710                    );
15711                    let suffix_range = comment_suffix_range(
15712                        snapshot.deref(),
15713                        end_row,
15714                        comment_suffix.trim_start_matches(' '),
15715                        comment_suffix.starts_with(' '),
15716                    );
15717
15718                    if prefix_range.is_empty() || suffix_range.is_empty() {
15719                        edits.push((
15720                            prefix_range.start..prefix_range.start,
15721                            full_comment_prefix.clone(),
15722                        ));
15723                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15724                        suffixes_inserted.push((end_row, comment_suffix.len()));
15725                    } else {
15726                        edits.push((prefix_range, empty_str.clone()));
15727                        edits.push((suffix_range, empty_str.clone()));
15728                    }
15729                } else {
15730                    continue;
15731                }
15732            }
15733
15734            drop(snapshot);
15735            this.buffer.update(cx, |buffer, cx| {
15736                buffer.edit(edits, None, cx);
15737            });
15738
15739            // Adjust selections so that they end before any comment suffixes that
15740            // were inserted.
15741            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15742            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15743            let snapshot = this.buffer.read(cx).read(cx);
15744            for selection in &mut selections {
15745                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15746                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15747                        Ordering::Less => {
15748                            suffixes_inserted.next();
15749                            continue;
15750                        }
15751                        Ordering::Greater => break,
15752                        Ordering::Equal => {
15753                            if selection.end.column == snapshot.line_len(row) {
15754                                if selection.is_empty() {
15755                                    selection.start.column -= suffix_len as u32;
15756                                }
15757                                selection.end.column -= suffix_len as u32;
15758                            }
15759                            break;
15760                        }
15761                    }
15762                }
15763            }
15764
15765            drop(snapshot);
15766            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15767
15768            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15769            let selections_on_single_row = selections.windows(2).all(|selections| {
15770                selections[0].start.row == selections[1].start.row
15771                    && selections[0].end.row == selections[1].end.row
15772                    && selections[0].start.row == selections[0].end.row
15773            });
15774            let selections_selecting = selections
15775                .iter()
15776                .any(|selection| selection.start != selection.end);
15777            let advance_downwards = action.advance_downwards
15778                && selections_on_single_row
15779                && !selections_selecting
15780                && !matches!(this.mode, EditorMode::SingleLine);
15781
15782            if advance_downwards {
15783                let snapshot = this.buffer.read(cx).snapshot(cx);
15784
15785                this.change_selections(Default::default(), window, cx, |s| {
15786                    s.move_cursors_with(|display_snapshot, display_point, _| {
15787                        let mut point = display_point.to_point(display_snapshot);
15788                        point.row += 1;
15789                        point = snapshot.clip_point(point, Bias::Left);
15790                        let display_point = point.to_display_point(display_snapshot);
15791                        let goal = SelectionGoal::HorizontalPosition(
15792                            display_snapshot
15793                                .x_for_display_point(display_point, text_layout_details)
15794                                .into(),
15795                        );
15796                        (display_point, goal)
15797                    })
15798                });
15799            }
15800        });
15801    }
15802
15803    pub fn select_enclosing_symbol(
15804        &mut self,
15805        _: &SelectEnclosingSymbol,
15806        window: &mut Window,
15807        cx: &mut Context<Self>,
15808    ) {
15809        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15810
15811        let buffer = self.buffer.read(cx).snapshot(cx);
15812        let old_selections = self
15813            .selections
15814            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15815            .into_boxed_slice();
15816
15817        fn update_selection(
15818            selection: &Selection<MultiBufferOffset>,
15819            buffer_snap: &MultiBufferSnapshot,
15820        ) -> Option<Selection<MultiBufferOffset>> {
15821            let cursor = selection.head();
15822            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15823            for symbol in symbols.iter().rev() {
15824                let start = symbol.range.start.to_offset(buffer_snap);
15825                let end = symbol.range.end.to_offset(buffer_snap);
15826                let new_range = start..end;
15827                if start < selection.start || end > selection.end {
15828                    return Some(Selection {
15829                        id: selection.id,
15830                        start: new_range.start,
15831                        end: new_range.end,
15832                        goal: SelectionGoal::None,
15833                        reversed: selection.reversed,
15834                    });
15835                }
15836            }
15837            None
15838        }
15839
15840        let mut selected_larger_symbol = false;
15841        let new_selections = old_selections
15842            .iter()
15843            .map(|selection| match update_selection(selection, &buffer) {
15844                Some(new_selection) => {
15845                    if new_selection.range() != selection.range() {
15846                        selected_larger_symbol = true;
15847                    }
15848                    new_selection
15849                }
15850                None => selection.clone(),
15851            })
15852            .collect::<Vec<_>>();
15853
15854        if selected_larger_symbol {
15855            self.change_selections(Default::default(), window, cx, |s| {
15856                s.select(new_selections);
15857            });
15858        }
15859    }
15860
15861    pub fn select_larger_syntax_node(
15862        &mut self,
15863        _: &SelectLargerSyntaxNode,
15864        window: &mut Window,
15865        cx: &mut Context<Self>,
15866    ) {
15867        let Some(visible_row_count) = self.visible_row_count() else {
15868            return;
15869        };
15870        let old_selections: Box<[_]> = self
15871            .selections
15872            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15873            .into();
15874        if old_selections.is_empty() {
15875            return;
15876        }
15877
15878        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15879
15880        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15881        let buffer = self.buffer.read(cx).snapshot(cx);
15882
15883        let mut selected_larger_node = false;
15884        let mut new_selections = old_selections
15885            .iter()
15886            .map(|selection| {
15887                let old_range = selection.start..selection.end;
15888
15889                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15890                    // manually select word at selection
15891                    if ["string_content", "inline"].contains(&node.kind()) {
15892                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15893                        // ignore if word is already selected
15894                        if !word_range.is_empty() && old_range != word_range {
15895                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15896                            // only select word if start and end point belongs to same word
15897                            if word_range == last_word_range {
15898                                selected_larger_node = true;
15899                                return Selection {
15900                                    id: selection.id,
15901                                    start: word_range.start,
15902                                    end: word_range.end,
15903                                    goal: SelectionGoal::None,
15904                                    reversed: selection.reversed,
15905                                };
15906                            }
15907                        }
15908                    }
15909                }
15910
15911                let mut new_range = old_range.clone();
15912                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15913                    new_range = range;
15914                    if !node.is_named() {
15915                        continue;
15916                    }
15917                    if !display_map.intersects_fold(new_range.start)
15918                        && !display_map.intersects_fold(new_range.end)
15919                    {
15920                        break;
15921                    }
15922                }
15923
15924                selected_larger_node |= new_range != old_range;
15925                Selection {
15926                    id: selection.id,
15927                    start: new_range.start,
15928                    end: new_range.end,
15929                    goal: SelectionGoal::None,
15930                    reversed: selection.reversed,
15931                }
15932            })
15933            .collect::<Vec<_>>();
15934
15935        if !selected_larger_node {
15936            return; // don't put this call in the history
15937        }
15938
15939        // scroll based on transformation done to the last selection created by the user
15940        let (last_old, last_new) = old_selections
15941            .last()
15942            .zip(new_selections.last().cloned())
15943            .expect("old_selections isn't empty");
15944
15945        // revert selection
15946        let is_selection_reversed = {
15947            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15948            new_selections.last_mut().expect("checked above").reversed =
15949                should_newest_selection_be_reversed;
15950            should_newest_selection_be_reversed
15951        };
15952
15953        if selected_larger_node {
15954            self.select_syntax_node_history.disable_clearing = true;
15955            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15956                s.select(new_selections.clone());
15957            });
15958            self.select_syntax_node_history.disable_clearing = false;
15959        }
15960
15961        let start_row = last_new.start.to_display_point(&display_map).row().0;
15962        let end_row = last_new.end.to_display_point(&display_map).row().0;
15963        let selection_height = end_row - start_row + 1;
15964        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15965
15966        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15967        let scroll_behavior = if fits_on_the_screen {
15968            self.request_autoscroll(Autoscroll::fit(), cx);
15969            SelectSyntaxNodeScrollBehavior::FitSelection
15970        } else if is_selection_reversed {
15971            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15972            SelectSyntaxNodeScrollBehavior::CursorTop
15973        } else {
15974            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15975            SelectSyntaxNodeScrollBehavior::CursorBottom
15976        };
15977
15978        self.select_syntax_node_history.push((
15979            old_selections,
15980            scroll_behavior,
15981            is_selection_reversed,
15982        ));
15983    }
15984
15985    pub fn select_smaller_syntax_node(
15986        &mut self,
15987        _: &SelectSmallerSyntaxNode,
15988        window: &mut Window,
15989        cx: &mut Context<Self>,
15990    ) {
15991        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15992
15993        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15994            self.select_syntax_node_history.pop()
15995        {
15996            if let Some(selection) = selections.last_mut() {
15997                selection.reversed = is_selection_reversed;
15998            }
15999
16000            self.select_syntax_node_history.disable_clearing = true;
16001            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16002                s.select(selections.to_vec());
16003            });
16004            self.select_syntax_node_history.disable_clearing = false;
16005
16006            match scroll_behavior {
16007                SelectSyntaxNodeScrollBehavior::CursorTop => {
16008                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16009                }
16010                SelectSyntaxNodeScrollBehavior::FitSelection => {
16011                    self.request_autoscroll(Autoscroll::fit(), cx);
16012                }
16013                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16014                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16015                }
16016            }
16017        }
16018    }
16019
16020    pub fn unwrap_syntax_node(
16021        &mut self,
16022        _: &UnwrapSyntaxNode,
16023        window: &mut Window,
16024        cx: &mut Context<Self>,
16025    ) {
16026        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16027
16028        let buffer = self.buffer.read(cx).snapshot(cx);
16029        let selections = self
16030            .selections
16031            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16032            .into_iter()
16033            // subtracting the offset requires sorting
16034            .sorted_by_key(|i| i.start);
16035
16036        let full_edits = selections
16037            .into_iter()
16038            .filter_map(|selection| {
16039                let child = if selection.is_empty()
16040                    && let Some((_, ancestor_range)) =
16041                        buffer.syntax_ancestor(selection.start..selection.end)
16042                {
16043                    ancestor_range
16044                } else {
16045                    selection.range()
16046                };
16047
16048                let mut parent = child.clone();
16049                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16050                    parent = ancestor_range;
16051                    if parent.start < child.start || parent.end > child.end {
16052                        break;
16053                    }
16054                }
16055
16056                if parent == child {
16057                    return None;
16058                }
16059                let text = buffer.text_for_range(child).collect::<String>();
16060                Some((selection.id, parent, text))
16061            })
16062            .collect::<Vec<_>>();
16063        if full_edits.is_empty() {
16064            return;
16065        }
16066
16067        self.transact(window, cx, |this, window, cx| {
16068            this.buffer.update(cx, |buffer, cx| {
16069                buffer.edit(
16070                    full_edits
16071                        .iter()
16072                        .map(|(_, p, t)| (p.clone(), t.clone()))
16073                        .collect::<Vec<_>>(),
16074                    None,
16075                    cx,
16076                );
16077            });
16078            this.change_selections(Default::default(), window, cx, |s| {
16079                let mut offset = 0;
16080                let mut selections = vec![];
16081                for (id, parent, text) in full_edits {
16082                    let start = parent.start - offset;
16083                    offset += (parent.end - parent.start) - text.len();
16084                    selections.push(Selection {
16085                        id,
16086                        start,
16087                        end: start + text.len(),
16088                        reversed: false,
16089                        goal: Default::default(),
16090                    });
16091                }
16092                s.select(selections);
16093            });
16094        });
16095    }
16096
16097    pub fn select_next_syntax_node(
16098        &mut self,
16099        _: &SelectNextSyntaxNode,
16100        window: &mut Window,
16101        cx: &mut Context<Self>,
16102    ) {
16103        let old_selections: Box<[_]> = self
16104            .selections
16105            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16106            .into();
16107        if old_selections.is_empty() {
16108            return;
16109        }
16110
16111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16112
16113        let buffer = self.buffer.read(cx).snapshot(cx);
16114        let mut selected_sibling = false;
16115
16116        let new_selections = old_selections
16117            .iter()
16118            .map(|selection| {
16119                let old_range = selection.start..selection.end;
16120
16121                let old_range =
16122                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16123                let excerpt = buffer.excerpt_containing(old_range.clone());
16124
16125                if let Some(mut excerpt) = excerpt
16126                    && let Some(node) = excerpt
16127                        .buffer()
16128                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16129                {
16130                    let new_range = excerpt.map_range_from_buffer(
16131                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16132                    );
16133                    selected_sibling = true;
16134                    Selection {
16135                        id: selection.id,
16136                        start: new_range.start,
16137                        end: new_range.end,
16138                        goal: SelectionGoal::None,
16139                        reversed: selection.reversed,
16140                    }
16141                } else {
16142                    selection.clone()
16143                }
16144            })
16145            .collect::<Vec<_>>();
16146
16147        if selected_sibling {
16148            self.change_selections(
16149                SelectionEffects::scroll(Autoscroll::fit()),
16150                window,
16151                cx,
16152                |s| {
16153                    s.select(new_selections);
16154                },
16155            );
16156        }
16157    }
16158
16159    pub fn select_prev_syntax_node(
16160        &mut self,
16161        _: &SelectPreviousSyntaxNode,
16162        window: &mut Window,
16163        cx: &mut Context<Self>,
16164    ) {
16165        let old_selections: Box<[_]> = self
16166            .selections
16167            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16168            .into();
16169        if old_selections.is_empty() {
16170            return;
16171        }
16172
16173        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16174
16175        let buffer = self.buffer.read(cx).snapshot(cx);
16176        let mut selected_sibling = false;
16177
16178        let new_selections = old_selections
16179            .iter()
16180            .map(|selection| {
16181                let old_range = selection.start..selection.end;
16182                let old_range =
16183                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16184                let excerpt = buffer.excerpt_containing(old_range.clone());
16185
16186                if let Some(mut excerpt) = excerpt
16187                    && let Some(node) = excerpt
16188                        .buffer()
16189                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16190                {
16191                    let new_range = excerpt.map_range_from_buffer(
16192                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16193                    );
16194                    selected_sibling = true;
16195                    Selection {
16196                        id: selection.id,
16197                        start: new_range.start,
16198                        end: new_range.end,
16199                        goal: SelectionGoal::None,
16200                        reversed: selection.reversed,
16201                    }
16202                } else {
16203                    selection.clone()
16204                }
16205            })
16206            .collect::<Vec<_>>();
16207
16208        if selected_sibling {
16209            self.change_selections(
16210                SelectionEffects::scroll(Autoscroll::fit()),
16211                window,
16212                cx,
16213                |s| {
16214                    s.select(new_selections);
16215                },
16216            );
16217        }
16218    }
16219
16220    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16221        if !EditorSettings::get_global(cx).gutter.runnables {
16222            self.clear_tasks();
16223            return Task::ready(());
16224        }
16225        let project = self.project().map(Entity::downgrade);
16226        let task_sources = self.lsp_task_sources(cx);
16227        let multi_buffer = self.buffer.downgrade();
16228        cx.spawn_in(window, async move |editor, cx| {
16229            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16230            let Some(project) = project.and_then(|p| p.upgrade()) else {
16231                return;
16232            };
16233            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16234                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16235            }) else {
16236                return;
16237            };
16238
16239            let hide_runnables = project
16240                .update(cx, |project, _| project.is_via_collab())
16241                .unwrap_or(true);
16242            if hide_runnables {
16243                return;
16244            }
16245            let new_rows =
16246                cx.background_spawn({
16247                    let snapshot = display_snapshot.clone();
16248                    async move {
16249                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16250                    }
16251                })
16252                    .await;
16253            let Ok(lsp_tasks) =
16254                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16255            else {
16256                return;
16257            };
16258            let lsp_tasks = lsp_tasks.await;
16259
16260            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16261                lsp_tasks
16262                    .into_iter()
16263                    .flat_map(|(kind, tasks)| {
16264                        tasks.into_iter().filter_map(move |(location, task)| {
16265                            Some((kind.clone(), location?, task))
16266                        })
16267                    })
16268                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16269                        let buffer = location.target.buffer;
16270                        let buffer_snapshot = buffer.read(cx).snapshot();
16271                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16272                            |(excerpt_id, snapshot, _)| {
16273                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16274                                    display_snapshot
16275                                        .buffer_snapshot()
16276                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16277                                } else {
16278                                    None
16279                                }
16280                            },
16281                        );
16282                        if let Some(offset) = offset {
16283                            let task_buffer_range =
16284                                location.target.range.to_point(&buffer_snapshot);
16285                            let context_buffer_range =
16286                                task_buffer_range.to_offset(&buffer_snapshot);
16287                            let context_range = BufferOffset(context_buffer_range.start)
16288                                ..BufferOffset(context_buffer_range.end);
16289
16290                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16291                                .or_insert_with(|| RunnableTasks {
16292                                    templates: Vec::new(),
16293                                    offset,
16294                                    column: task_buffer_range.start.column,
16295                                    extra_variables: HashMap::default(),
16296                                    context_range,
16297                                })
16298                                .templates
16299                                .push((kind, task.original_task().clone()));
16300                        }
16301
16302                        acc
16303                    })
16304            }) else {
16305                return;
16306            };
16307
16308            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16309                buffer.language_settings(cx).tasks.prefer_lsp
16310            }) else {
16311                return;
16312            };
16313
16314            let rows = Self::runnable_rows(
16315                project,
16316                display_snapshot,
16317                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16318                new_rows,
16319                cx.clone(),
16320            )
16321            .await;
16322            editor
16323                .update(cx, |editor, _| {
16324                    editor.clear_tasks();
16325                    for (key, mut value) in rows {
16326                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16327                            value.templates.extend(lsp_tasks.templates);
16328                        }
16329
16330                        editor.insert_tasks(key, value);
16331                    }
16332                    for (key, value) in lsp_tasks_by_rows {
16333                        editor.insert_tasks(key, value);
16334                    }
16335                })
16336                .ok();
16337        })
16338    }
16339    fn fetch_runnable_ranges(
16340        snapshot: &DisplaySnapshot,
16341        range: Range<Anchor>,
16342    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16343        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16344    }
16345
16346    fn runnable_rows(
16347        project: Entity<Project>,
16348        snapshot: DisplaySnapshot,
16349        prefer_lsp: bool,
16350        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16351        cx: AsyncWindowContext,
16352    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16353        cx.spawn(async move |cx| {
16354            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16355            for (run_range, mut runnable) in runnable_ranges {
16356                let Some(tasks) = cx
16357                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16358                    .ok()
16359                else {
16360                    continue;
16361                };
16362                let mut tasks = tasks.await;
16363
16364                if prefer_lsp {
16365                    tasks.retain(|(task_kind, _)| {
16366                        !matches!(task_kind, TaskSourceKind::Language { .. })
16367                    });
16368                }
16369                if tasks.is_empty() {
16370                    continue;
16371                }
16372
16373                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16374                let Some(row) = snapshot
16375                    .buffer_snapshot()
16376                    .buffer_line_for_row(MultiBufferRow(point.row))
16377                    .map(|(_, range)| range.start.row)
16378                else {
16379                    continue;
16380                };
16381
16382                let context_range =
16383                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16384                runnable_rows.push((
16385                    (runnable.buffer_id, row),
16386                    RunnableTasks {
16387                        templates: tasks,
16388                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16389                        context_range,
16390                        column: point.column,
16391                        extra_variables: runnable.extra_captures,
16392                    },
16393                ));
16394            }
16395            runnable_rows
16396        })
16397    }
16398
16399    fn templates_with_tags(
16400        project: &Entity<Project>,
16401        runnable: &mut Runnable,
16402        cx: &mut App,
16403    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16404        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16405            let (worktree_id, file) = project
16406                .buffer_for_id(runnable.buffer, cx)
16407                .and_then(|buffer| buffer.read(cx).file())
16408                .map(|file| (file.worktree_id(cx), file.clone()))
16409                .unzip();
16410
16411            (
16412                project.task_store().read(cx).task_inventory().cloned(),
16413                worktree_id,
16414                file,
16415            )
16416        });
16417
16418        let tags = mem::take(&mut runnable.tags);
16419        let language = runnable.language.clone();
16420        cx.spawn(async move |cx| {
16421            let mut templates_with_tags = Vec::new();
16422            if let Some(inventory) = inventory {
16423                for RunnableTag(tag) in tags {
16424                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16425                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16426                    }) else {
16427                        return templates_with_tags;
16428                    };
16429                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16430                        move |(_, template)| {
16431                            template.tags.iter().any(|source_tag| source_tag == &tag)
16432                        },
16433                    ));
16434                }
16435            }
16436            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16437
16438            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16439                // Strongest source wins; if we have worktree tag binding, prefer that to
16440                // global and language bindings;
16441                // if we have a global binding, prefer that to language binding.
16442                let first_mismatch = templates_with_tags
16443                    .iter()
16444                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16445                if let Some(index) = first_mismatch {
16446                    templates_with_tags.truncate(index);
16447                }
16448            }
16449
16450            templates_with_tags
16451        })
16452    }
16453
16454    pub fn move_to_enclosing_bracket(
16455        &mut self,
16456        _: &MoveToEnclosingBracket,
16457        window: &mut Window,
16458        cx: &mut Context<Self>,
16459    ) {
16460        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16461        self.change_selections(Default::default(), window, cx, |s| {
16462            s.move_offsets_with(|snapshot, selection| {
16463                let Some(enclosing_bracket_ranges) =
16464                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16465                else {
16466                    return;
16467                };
16468
16469                let mut best_length = usize::MAX;
16470                let mut best_inside = false;
16471                let mut best_in_bracket_range = false;
16472                let mut best_destination = None;
16473                for (open, close) in enclosing_bracket_ranges {
16474                    let close = close.to_inclusive();
16475                    let length = *close.end() - open.start;
16476                    let inside = selection.start >= open.end && selection.end <= *close.start();
16477                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16478                        || close.contains(&selection.head());
16479
16480                    // If best is next to a bracket and current isn't, skip
16481                    if !in_bracket_range && best_in_bracket_range {
16482                        continue;
16483                    }
16484
16485                    // Prefer smaller lengths unless best is inside and current isn't
16486                    if length > best_length && (best_inside || !inside) {
16487                        continue;
16488                    }
16489
16490                    best_length = length;
16491                    best_inside = inside;
16492                    best_in_bracket_range = in_bracket_range;
16493                    best_destination = Some(
16494                        if close.contains(&selection.start) && close.contains(&selection.end) {
16495                            if inside { open.end } else { open.start }
16496                        } else if inside {
16497                            *close.start()
16498                        } else {
16499                            *close.end()
16500                        },
16501                    );
16502                }
16503
16504                if let Some(destination) = best_destination {
16505                    selection.collapse_to(destination, SelectionGoal::None);
16506                }
16507            })
16508        });
16509    }
16510
16511    pub fn undo_selection(
16512        &mut self,
16513        _: &UndoSelection,
16514        window: &mut Window,
16515        cx: &mut Context<Self>,
16516    ) {
16517        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16518        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16519            self.selection_history.mode = SelectionHistoryMode::Undoing;
16520            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16521                this.end_selection(window, cx);
16522                this.change_selections(
16523                    SelectionEffects::scroll(Autoscroll::newest()),
16524                    window,
16525                    cx,
16526                    |s| s.select_anchors(entry.selections.to_vec()),
16527                );
16528            });
16529            self.selection_history.mode = SelectionHistoryMode::Normal;
16530
16531            self.select_next_state = entry.select_next_state;
16532            self.select_prev_state = entry.select_prev_state;
16533            self.add_selections_state = entry.add_selections_state;
16534        }
16535    }
16536
16537    pub fn redo_selection(
16538        &mut self,
16539        _: &RedoSelection,
16540        window: &mut Window,
16541        cx: &mut Context<Self>,
16542    ) {
16543        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16544        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16545            self.selection_history.mode = SelectionHistoryMode::Redoing;
16546            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16547                this.end_selection(window, cx);
16548                this.change_selections(
16549                    SelectionEffects::scroll(Autoscroll::newest()),
16550                    window,
16551                    cx,
16552                    |s| s.select_anchors(entry.selections.to_vec()),
16553                );
16554            });
16555            self.selection_history.mode = SelectionHistoryMode::Normal;
16556
16557            self.select_next_state = entry.select_next_state;
16558            self.select_prev_state = entry.select_prev_state;
16559            self.add_selections_state = entry.add_selections_state;
16560        }
16561    }
16562
16563    pub fn expand_excerpts(
16564        &mut self,
16565        action: &ExpandExcerpts,
16566        _: &mut Window,
16567        cx: &mut Context<Self>,
16568    ) {
16569        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16570    }
16571
16572    pub fn expand_excerpts_down(
16573        &mut self,
16574        action: &ExpandExcerptsDown,
16575        _: &mut Window,
16576        cx: &mut Context<Self>,
16577    ) {
16578        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16579    }
16580
16581    pub fn expand_excerpts_up(
16582        &mut self,
16583        action: &ExpandExcerptsUp,
16584        _: &mut Window,
16585        cx: &mut Context<Self>,
16586    ) {
16587        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16588    }
16589
16590    pub fn expand_excerpts_for_direction(
16591        &mut self,
16592        lines: u32,
16593        direction: ExpandExcerptDirection,
16594
16595        cx: &mut Context<Self>,
16596    ) {
16597        let selections = self.selections.disjoint_anchors_arc();
16598
16599        let lines = if lines == 0 {
16600            EditorSettings::get_global(cx).expand_excerpt_lines
16601        } else {
16602            lines
16603        };
16604
16605        self.buffer.update(cx, |buffer, cx| {
16606            let snapshot = buffer.snapshot(cx);
16607            let mut excerpt_ids = selections
16608                .iter()
16609                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16610                .collect::<Vec<_>>();
16611            excerpt_ids.sort();
16612            excerpt_ids.dedup();
16613            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16614        })
16615    }
16616
16617    pub fn expand_excerpt(
16618        &mut self,
16619        excerpt: ExcerptId,
16620        direction: ExpandExcerptDirection,
16621        window: &mut Window,
16622        cx: &mut Context<Self>,
16623    ) {
16624        let current_scroll_position = self.scroll_position(cx);
16625        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16626        let mut scroll = None;
16627
16628        if direction == ExpandExcerptDirection::Down {
16629            let multi_buffer = self.buffer.read(cx);
16630            let snapshot = multi_buffer.snapshot(cx);
16631            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16632                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16633                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16634            {
16635                let buffer_snapshot = buffer.read(cx).snapshot();
16636                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16637                let last_row = buffer_snapshot.max_point().row;
16638                let lines_below = last_row.saturating_sub(excerpt_end_row);
16639                if lines_below >= lines_to_expand {
16640                    scroll = Some(
16641                        current_scroll_position
16642                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16643                    );
16644                }
16645            }
16646        }
16647        if direction == ExpandExcerptDirection::Up
16648            && self
16649                .buffer
16650                .read(cx)
16651                .snapshot(cx)
16652                .excerpt_before(excerpt)
16653                .is_none()
16654        {
16655            scroll = Some(current_scroll_position);
16656        }
16657
16658        self.buffer.update(cx, |buffer, cx| {
16659            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16660        });
16661
16662        if let Some(new_scroll_position) = scroll {
16663            self.set_scroll_position(new_scroll_position, window, cx);
16664        }
16665    }
16666
16667    pub fn go_to_singleton_buffer_point(
16668        &mut self,
16669        point: Point,
16670        window: &mut Window,
16671        cx: &mut Context<Self>,
16672    ) {
16673        self.go_to_singleton_buffer_range(point..point, window, cx);
16674    }
16675
16676    pub fn go_to_singleton_buffer_range(
16677        &mut self,
16678        range: Range<Point>,
16679        window: &mut Window,
16680        cx: &mut Context<Self>,
16681    ) {
16682        let multibuffer = self.buffer().read(cx);
16683        let Some(buffer) = multibuffer.as_singleton() else {
16684            return;
16685        };
16686        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16687            return;
16688        };
16689        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16690            return;
16691        };
16692        self.change_selections(
16693            SelectionEffects::default().nav_history(true),
16694            window,
16695            cx,
16696            |s| s.select_anchor_ranges([start..end]),
16697        );
16698    }
16699
16700    pub fn go_to_diagnostic(
16701        &mut self,
16702        action: &GoToDiagnostic,
16703        window: &mut Window,
16704        cx: &mut Context<Self>,
16705    ) {
16706        if !self.diagnostics_enabled() {
16707            return;
16708        }
16709        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16710        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16711    }
16712
16713    pub fn go_to_prev_diagnostic(
16714        &mut self,
16715        action: &GoToPreviousDiagnostic,
16716        window: &mut Window,
16717        cx: &mut Context<Self>,
16718    ) {
16719        if !self.diagnostics_enabled() {
16720            return;
16721        }
16722        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16723        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16724    }
16725
16726    pub fn go_to_diagnostic_impl(
16727        &mut self,
16728        direction: Direction,
16729        severity: GoToDiagnosticSeverityFilter,
16730        window: &mut Window,
16731        cx: &mut Context<Self>,
16732    ) {
16733        let buffer = self.buffer.read(cx).snapshot(cx);
16734        let selection = self
16735            .selections
16736            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16737
16738        let mut active_group_id = None;
16739        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16740            && active_group.active_range.start.to_offset(&buffer) == selection.start
16741        {
16742            active_group_id = Some(active_group.group_id);
16743        }
16744
16745        fn filtered<'a>(
16746            severity: GoToDiagnosticSeverityFilter,
16747            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16748        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16749            diagnostics
16750                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16751                .filter(|entry| entry.range.start != entry.range.end)
16752                .filter(|entry| !entry.diagnostic.is_unnecessary)
16753        }
16754
16755        let before = filtered(
16756            severity,
16757            buffer
16758                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16759                .filter(|entry| entry.range.start <= selection.start),
16760        );
16761        let after = filtered(
16762            severity,
16763            buffer
16764                .diagnostics_in_range(selection.start..buffer.len())
16765                .filter(|entry| entry.range.start >= selection.start),
16766        );
16767
16768        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16769        if direction == Direction::Prev {
16770            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16771            {
16772                for diagnostic in prev_diagnostics.into_iter().rev() {
16773                    if diagnostic.range.start != selection.start
16774                        || active_group_id
16775                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16776                    {
16777                        found = Some(diagnostic);
16778                        break 'outer;
16779                    }
16780                }
16781            }
16782        } else {
16783            for diagnostic in after.chain(before) {
16784                if diagnostic.range.start != selection.start
16785                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16786                {
16787                    found = Some(diagnostic);
16788                    break;
16789                }
16790            }
16791        }
16792        let Some(next_diagnostic) = found else {
16793            return;
16794        };
16795
16796        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16797        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16798            return;
16799        };
16800        let snapshot = self.snapshot(window, cx);
16801        if snapshot.intersects_fold(next_diagnostic.range.start) {
16802            self.unfold_ranges(
16803                std::slice::from_ref(&next_diagnostic.range),
16804                true,
16805                false,
16806                cx,
16807            );
16808        }
16809        self.change_selections(Default::default(), window, cx, |s| {
16810            s.select_ranges(vec![
16811                next_diagnostic.range.start..next_diagnostic.range.start,
16812            ])
16813        });
16814        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16815        self.refresh_edit_prediction(false, true, window, cx);
16816    }
16817
16818    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16819        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16820        let snapshot = self.snapshot(window, cx);
16821        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16822        self.go_to_hunk_before_or_after_position(
16823            &snapshot,
16824            selection.head(),
16825            Direction::Next,
16826            window,
16827            cx,
16828        );
16829    }
16830
16831    pub fn go_to_hunk_before_or_after_position(
16832        &mut self,
16833        snapshot: &EditorSnapshot,
16834        position: Point,
16835        direction: Direction,
16836        window: &mut Window,
16837        cx: &mut Context<Editor>,
16838    ) {
16839        let row = if direction == Direction::Next {
16840            self.hunk_after_position(snapshot, position)
16841                .map(|hunk| hunk.row_range.start)
16842        } else {
16843            self.hunk_before_position(snapshot, position)
16844        };
16845
16846        if let Some(row) = row {
16847            let destination = Point::new(row.0, 0);
16848            let autoscroll = Autoscroll::center();
16849
16850            self.unfold_ranges(&[destination..destination], false, false, cx);
16851            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16852                s.select_ranges([destination..destination]);
16853            });
16854        }
16855    }
16856
16857    fn hunk_after_position(
16858        &mut self,
16859        snapshot: &EditorSnapshot,
16860        position: Point,
16861    ) -> Option<MultiBufferDiffHunk> {
16862        snapshot
16863            .buffer_snapshot()
16864            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16865            .find(|hunk| hunk.row_range.start.0 > position.row)
16866            .or_else(|| {
16867                snapshot
16868                    .buffer_snapshot()
16869                    .diff_hunks_in_range(Point::zero()..position)
16870                    .find(|hunk| hunk.row_range.end.0 < position.row)
16871            })
16872    }
16873
16874    fn go_to_prev_hunk(
16875        &mut self,
16876        _: &GoToPreviousHunk,
16877        window: &mut Window,
16878        cx: &mut Context<Self>,
16879    ) {
16880        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16881        let snapshot = self.snapshot(window, cx);
16882        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16883        self.go_to_hunk_before_or_after_position(
16884            &snapshot,
16885            selection.head(),
16886            Direction::Prev,
16887            window,
16888            cx,
16889        );
16890    }
16891
16892    fn hunk_before_position(
16893        &mut self,
16894        snapshot: &EditorSnapshot,
16895        position: Point,
16896    ) -> Option<MultiBufferRow> {
16897        snapshot
16898            .buffer_snapshot()
16899            .diff_hunk_before(position)
16900            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16901    }
16902
16903    fn go_to_next_change(
16904        &mut self,
16905        _: &GoToNextChange,
16906        window: &mut Window,
16907        cx: &mut Context<Self>,
16908    ) {
16909        if let Some(selections) = self
16910            .change_list
16911            .next_change(1, Direction::Next)
16912            .map(|s| s.to_vec())
16913        {
16914            self.change_selections(Default::default(), window, cx, |s| {
16915                let map = s.display_snapshot();
16916                s.select_display_ranges(selections.iter().map(|a| {
16917                    let point = a.to_display_point(&map);
16918                    point..point
16919                }))
16920            })
16921        }
16922    }
16923
16924    fn go_to_previous_change(
16925        &mut self,
16926        _: &GoToPreviousChange,
16927        window: &mut Window,
16928        cx: &mut Context<Self>,
16929    ) {
16930        if let Some(selections) = self
16931            .change_list
16932            .next_change(1, Direction::Prev)
16933            .map(|s| s.to_vec())
16934        {
16935            self.change_selections(Default::default(), window, cx, |s| {
16936                let map = s.display_snapshot();
16937                s.select_display_ranges(selections.iter().map(|a| {
16938                    let point = a.to_display_point(&map);
16939                    point..point
16940                }))
16941            })
16942        }
16943    }
16944
16945    pub fn go_to_next_document_highlight(
16946        &mut self,
16947        _: &GoToNextDocumentHighlight,
16948        window: &mut Window,
16949        cx: &mut Context<Self>,
16950    ) {
16951        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16952    }
16953
16954    pub fn go_to_prev_document_highlight(
16955        &mut self,
16956        _: &GoToPreviousDocumentHighlight,
16957        window: &mut Window,
16958        cx: &mut Context<Self>,
16959    ) {
16960        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16961    }
16962
16963    pub fn go_to_document_highlight_before_or_after_position(
16964        &mut self,
16965        direction: Direction,
16966        window: &mut Window,
16967        cx: &mut Context<Editor>,
16968    ) {
16969        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16970        let snapshot = self.snapshot(window, cx);
16971        let buffer = &snapshot.buffer_snapshot();
16972        let position = self
16973            .selections
16974            .newest::<Point>(&snapshot.display_snapshot)
16975            .head();
16976        let anchor_position = buffer.anchor_after(position);
16977
16978        // Get all document highlights (both read and write)
16979        let mut all_highlights = Vec::new();
16980
16981        if let Some((_, read_highlights)) = self
16982            .background_highlights
16983            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16984        {
16985            all_highlights.extend(read_highlights.iter());
16986        }
16987
16988        if let Some((_, write_highlights)) = self
16989            .background_highlights
16990            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16991        {
16992            all_highlights.extend(write_highlights.iter());
16993        }
16994
16995        if all_highlights.is_empty() {
16996            return;
16997        }
16998
16999        // Sort highlights by position
17000        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17001
17002        let target_highlight = match direction {
17003            Direction::Next => {
17004                // Find the first highlight after the current position
17005                all_highlights
17006                    .iter()
17007                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17008            }
17009            Direction::Prev => {
17010                // Find the last highlight before the current position
17011                all_highlights
17012                    .iter()
17013                    .rev()
17014                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17015            }
17016        };
17017
17018        if let Some(highlight) = target_highlight {
17019            let destination = highlight.start.to_point(buffer);
17020            let autoscroll = Autoscroll::center();
17021
17022            self.unfold_ranges(&[destination..destination], false, false, cx);
17023            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17024                s.select_ranges([destination..destination]);
17025            });
17026        }
17027    }
17028
17029    fn go_to_line<T: 'static>(
17030        &mut self,
17031        position: Anchor,
17032        highlight_color: Option<Hsla>,
17033        window: &mut Window,
17034        cx: &mut Context<Self>,
17035    ) {
17036        let snapshot = self.snapshot(window, cx).display_snapshot;
17037        let position = position.to_point(&snapshot.buffer_snapshot());
17038        let start = snapshot
17039            .buffer_snapshot()
17040            .clip_point(Point::new(position.row, 0), Bias::Left);
17041        let end = start + Point::new(1, 0);
17042        let start = snapshot.buffer_snapshot().anchor_before(start);
17043        let end = snapshot.buffer_snapshot().anchor_before(end);
17044
17045        self.highlight_rows::<T>(
17046            start..end,
17047            highlight_color
17048                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17049            Default::default(),
17050            cx,
17051        );
17052
17053        if self.buffer.read(cx).is_singleton() {
17054            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17055        }
17056    }
17057
17058    pub fn go_to_definition(
17059        &mut self,
17060        _: &GoToDefinition,
17061        window: &mut Window,
17062        cx: &mut Context<Self>,
17063    ) -> Task<Result<Navigated>> {
17064        let definition =
17065            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17066        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17067        cx.spawn_in(window, async move |editor, cx| {
17068            if definition.await? == Navigated::Yes {
17069                return Ok(Navigated::Yes);
17070            }
17071            match fallback_strategy {
17072                GoToDefinitionFallback::None => Ok(Navigated::No),
17073                GoToDefinitionFallback::FindAllReferences => {
17074                    match editor.update_in(cx, |editor, window, cx| {
17075                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17076                    })? {
17077                        Some(references) => references.await,
17078                        None => Ok(Navigated::No),
17079                    }
17080                }
17081            }
17082        })
17083    }
17084
17085    pub fn go_to_declaration(
17086        &mut self,
17087        _: &GoToDeclaration,
17088        window: &mut Window,
17089        cx: &mut Context<Self>,
17090    ) -> Task<Result<Navigated>> {
17091        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17092    }
17093
17094    pub fn go_to_declaration_split(
17095        &mut self,
17096        _: &GoToDeclaration,
17097        window: &mut Window,
17098        cx: &mut Context<Self>,
17099    ) -> Task<Result<Navigated>> {
17100        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17101    }
17102
17103    pub fn go_to_implementation(
17104        &mut self,
17105        _: &GoToImplementation,
17106        window: &mut Window,
17107        cx: &mut Context<Self>,
17108    ) -> Task<Result<Navigated>> {
17109        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17110    }
17111
17112    pub fn go_to_implementation_split(
17113        &mut self,
17114        _: &GoToImplementationSplit,
17115        window: &mut Window,
17116        cx: &mut Context<Self>,
17117    ) -> Task<Result<Navigated>> {
17118        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17119    }
17120
17121    pub fn go_to_type_definition(
17122        &mut self,
17123        _: &GoToTypeDefinition,
17124        window: &mut Window,
17125        cx: &mut Context<Self>,
17126    ) -> Task<Result<Navigated>> {
17127        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17128    }
17129
17130    pub fn go_to_definition_split(
17131        &mut self,
17132        _: &GoToDefinitionSplit,
17133        window: &mut Window,
17134        cx: &mut Context<Self>,
17135    ) -> Task<Result<Navigated>> {
17136        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17137    }
17138
17139    pub fn go_to_type_definition_split(
17140        &mut self,
17141        _: &GoToTypeDefinitionSplit,
17142        window: &mut Window,
17143        cx: &mut Context<Self>,
17144    ) -> Task<Result<Navigated>> {
17145        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17146    }
17147
17148    fn go_to_definition_of_kind(
17149        &mut self,
17150        kind: GotoDefinitionKind,
17151        split: bool,
17152        window: &mut Window,
17153        cx: &mut Context<Self>,
17154    ) -> Task<Result<Navigated>> {
17155        let Some(provider) = self.semantics_provider.clone() else {
17156            return Task::ready(Ok(Navigated::No));
17157        };
17158        let head = self
17159            .selections
17160            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17161            .head();
17162        let buffer = self.buffer.read(cx);
17163        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17164            return Task::ready(Ok(Navigated::No));
17165        };
17166        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17167            return Task::ready(Ok(Navigated::No));
17168        };
17169
17170        cx.spawn_in(window, async move |editor, cx| {
17171            let Some(definitions) = definitions.await? else {
17172                return Ok(Navigated::No);
17173            };
17174            let navigated = editor
17175                .update_in(cx, |editor, window, cx| {
17176                    editor.navigate_to_hover_links(
17177                        Some(kind),
17178                        definitions
17179                            .into_iter()
17180                            .filter(|location| {
17181                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17182                            })
17183                            .map(HoverLink::Text)
17184                            .collect::<Vec<_>>(),
17185                        split,
17186                        window,
17187                        cx,
17188                    )
17189                })?
17190                .await?;
17191            anyhow::Ok(navigated)
17192        })
17193    }
17194
17195    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17196        let selection = self.selections.newest_anchor();
17197        let head = selection.head();
17198        let tail = selection.tail();
17199
17200        let Some((buffer, start_position)) =
17201            self.buffer.read(cx).text_anchor_for_position(head, cx)
17202        else {
17203            return;
17204        };
17205
17206        let end_position = if head != tail {
17207            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17208                return;
17209            };
17210            Some(pos)
17211        } else {
17212            None
17213        };
17214
17215        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17216            let url = if let Some(end_pos) = end_position {
17217                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17218            } else {
17219                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17220            };
17221
17222            if let Some(url) = url {
17223                cx.update(|window, cx| {
17224                    if parse_zed_link(&url, cx).is_some() {
17225                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17226                    } else {
17227                        cx.open_url(&url);
17228                    }
17229                })?;
17230            }
17231
17232            anyhow::Ok(())
17233        });
17234
17235        url_finder.detach();
17236    }
17237
17238    pub fn open_selected_filename(
17239        &mut self,
17240        _: &OpenSelectedFilename,
17241        window: &mut Window,
17242        cx: &mut Context<Self>,
17243    ) {
17244        let Some(workspace) = self.workspace() else {
17245            return;
17246        };
17247
17248        let position = self.selections.newest_anchor().head();
17249
17250        let Some((buffer, buffer_position)) =
17251            self.buffer.read(cx).text_anchor_for_position(position, cx)
17252        else {
17253            return;
17254        };
17255
17256        let project = self.project.clone();
17257
17258        cx.spawn_in(window, async move |_, cx| {
17259            let result = find_file(&buffer, project, buffer_position, cx).await;
17260
17261            if let Some((_, path)) = result {
17262                workspace
17263                    .update_in(cx, |workspace, window, cx| {
17264                        workspace.open_resolved_path(path, window, cx)
17265                    })?
17266                    .await?;
17267            }
17268            anyhow::Ok(())
17269        })
17270        .detach();
17271    }
17272
17273    pub(crate) fn navigate_to_hover_links(
17274        &mut self,
17275        kind: Option<GotoDefinitionKind>,
17276        definitions: Vec<HoverLink>,
17277        split: bool,
17278        window: &mut Window,
17279        cx: &mut Context<Editor>,
17280    ) -> Task<Result<Navigated>> {
17281        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17282        let mut first_url_or_file = None;
17283        let definitions: Vec<_> = definitions
17284            .into_iter()
17285            .filter_map(|def| match def {
17286                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17287                HoverLink::InlayHint(lsp_location, server_id) => {
17288                    let computation =
17289                        self.compute_target_location(lsp_location, server_id, window, cx);
17290                    Some(cx.background_spawn(computation))
17291                }
17292                HoverLink::Url(url) => {
17293                    first_url_or_file = Some(Either::Left(url));
17294                    None
17295                }
17296                HoverLink::File(path) => {
17297                    first_url_or_file = Some(Either::Right(path));
17298                    None
17299                }
17300            })
17301            .collect();
17302
17303        let workspace = self.workspace();
17304
17305        cx.spawn_in(window, async move |editor, cx| {
17306            let locations: Vec<Location> = future::join_all(definitions)
17307                .await
17308                .into_iter()
17309                .filter_map(|location| location.transpose())
17310                .collect::<Result<_>>()
17311                .context("location tasks")?;
17312            let mut locations = cx.update(|_, cx| {
17313                locations
17314                    .into_iter()
17315                    .map(|location| {
17316                        let buffer = location.buffer.read(cx);
17317                        (location.buffer, location.range.to_point(buffer))
17318                    })
17319                    .into_group_map()
17320            })?;
17321            let mut num_locations = 0;
17322            for ranges in locations.values_mut() {
17323                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17324                ranges.dedup();
17325                num_locations += ranges.len();
17326            }
17327
17328            if num_locations > 1 {
17329                let tab_kind = match kind {
17330                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17331                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17332                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17333                    Some(GotoDefinitionKind::Type) => "Types",
17334                };
17335                let title = editor
17336                    .update_in(cx, |_, _, cx| {
17337                        let target = locations
17338                            .iter()
17339                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17340                            .map(|(buffer, location)| {
17341                                buffer
17342                                    .read(cx)
17343                                    .text_for_range(location.clone())
17344                                    .collect::<String>()
17345                            })
17346                            .filter(|text| !text.contains('\n'))
17347                            .unique()
17348                            .take(3)
17349                            .join(", ");
17350                        if target.is_empty() {
17351                            tab_kind.to_owned()
17352                        } else {
17353                            format!("{tab_kind} for {target}")
17354                        }
17355                    })
17356                    .context("buffer title")?;
17357
17358                let Some(workspace) = workspace else {
17359                    return Ok(Navigated::No);
17360                };
17361
17362                let opened = workspace
17363                    .update_in(cx, |workspace, window, cx| {
17364                        let allow_preview = PreviewTabsSettings::get_global(cx)
17365                            .enable_preview_multibuffer_from_code_navigation;
17366                        Self::open_locations_in_multibuffer(
17367                            workspace,
17368                            locations,
17369                            title,
17370                            split,
17371                            allow_preview,
17372                            MultibufferSelectionMode::First,
17373                            window,
17374                            cx,
17375                        )
17376                    })
17377                    .is_ok();
17378
17379                anyhow::Ok(Navigated::from_bool(opened))
17380            } else if num_locations == 0 {
17381                // If there is one url or file, open it directly
17382                match first_url_or_file {
17383                    Some(Either::Left(url)) => {
17384                        cx.update(|window, cx| {
17385                            if parse_zed_link(&url, cx).is_some() {
17386                                window
17387                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17388                            } else {
17389                                cx.open_url(&url);
17390                            }
17391                        })?;
17392                        Ok(Navigated::Yes)
17393                    }
17394                    Some(Either::Right(path)) => {
17395                        // TODO(andrew): respect preview tab settings
17396                        //               `enable_keep_preview_on_code_navigation` and
17397                        //               `enable_preview_file_from_code_navigation`
17398                        let Some(workspace) = workspace else {
17399                            return Ok(Navigated::No);
17400                        };
17401                        workspace
17402                            .update_in(cx, |workspace, window, cx| {
17403                                workspace.open_resolved_path(path, window, cx)
17404                            })?
17405                            .await?;
17406                        Ok(Navigated::Yes)
17407                    }
17408                    None => Ok(Navigated::No),
17409                }
17410            } else {
17411                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17412                let target_range = target_ranges.first().unwrap().clone();
17413
17414                editor.update_in(cx, |editor, window, cx| {
17415                    let range = target_range.to_point(target_buffer.read(cx));
17416                    let range = editor.range_for_match(&range);
17417                    let range = collapse_multiline_range(range);
17418
17419                    if !split
17420                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17421                    {
17422                        editor.go_to_singleton_buffer_range(range, window, cx);
17423                    } else {
17424                        let Some(workspace) = workspace else {
17425                            return Navigated::No;
17426                        };
17427                        let pane = workspace.read(cx).active_pane().clone();
17428                        window.defer(cx, move |window, cx| {
17429                            let target_editor: Entity<Self> =
17430                                workspace.update(cx, |workspace, cx| {
17431                                    let pane = if split {
17432                                        workspace.adjacent_pane(window, cx)
17433                                    } else {
17434                                        workspace.active_pane().clone()
17435                                    };
17436
17437                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17438                                    let keep_old_preview = preview_tabs_settings
17439                                        .enable_keep_preview_on_code_navigation;
17440                                    let allow_new_preview = preview_tabs_settings
17441                                        .enable_preview_file_from_code_navigation;
17442
17443                                    workspace.open_project_item(
17444                                        pane,
17445                                        target_buffer.clone(),
17446                                        true,
17447                                        true,
17448                                        keep_old_preview,
17449                                        allow_new_preview,
17450                                        window,
17451                                        cx,
17452                                    )
17453                                });
17454                            target_editor.update(cx, |target_editor, cx| {
17455                                // When selecting a definition in a different buffer, disable the nav history
17456                                // to avoid creating a history entry at the previous cursor location.
17457                                pane.update(cx, |pane, _| pane.disable_history());
17458                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17459                                pane.update(cx, |pane, _| pane.enable_history());
17460                            });
17461                        });
17462                    }
17463                    Navigated::Yes
17464                })
17465            }
17466        })
17467    }
17468
17469    fn compute_target_location(
17470        &self,
17471        lsp_location: lsp::Location,
17472        server_id: LanguageServerId,
17473        window: &mut Window,
17474        cx: &mut Context<Self>,
17475    ) -> Task<anyhow::Result<Option<Location>>> {
17476        let Some(project) = self.project.clone() else {
17477            return Task::ready(Ok(None));
17478        };
17479
17480        cx.spawn_in(window, async move |editor, cx| {
17481            let location_task = editor.update(cx, |_, cx| {
17482                project.update(cx, |project, cx| {
17483                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17484                })
17485            })?;
17486            let location = Some({
17487                let target_buffer_handle = location_task.await.context("open local buffer")?;
17488                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17489                    let target_start = target_buffer
17490                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17491                    let target_end = target_buffer
17492                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17493                    target_buffer.anchor_after(target_start)
17494                        ..target_buffer.anchor_before(target_end)
17495                })?;
17496                Location {
17497                    buffer: target_buffer_handle,
17498                    range,
17499                }
17500            });
17501            Ok(location)
17502        })
17503    }
17504
17505    fn go_to_next_reference(
17506        &mut self,
17507        _: &GoToNextReference,
17508        window: &mut Window,
17509        cx: &mut Context<Self>,
17510    ) {
17511        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17512        if let Some(task) = task {
17513            task.detach();
17514        };
17515    }
17516
17517    fn go_to_prev_reference(
17518        &mut self,
17519        _: &GoToPreviousReference,
17520        window: &mut Window,
17521        cx: &mut Context<Self>,
17522    ) {
17523        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17524        if let Some(task) = task {
17525            task.detach();
17526        };
17527    }
17528
17529    pub fn go_to_reference_before_or_after_position(
17530        &mut self,
17531        direction: Direction,
17532        count: usize,
17533        window: &mut Window,
17534        cx: &mut Context<Self>,
17535    ) -> Option<Task<Result<()>>> {
17536        let selection = self.selections.newest_anchor();
17537        let head = selection.head();
17538
17539        let multi_buffer = self.buffer.read(cx);
17540
17541        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17542        let workspace = self.workspace()?;
17543        let project = workspace.read(cx).project().clone();
17544        let references =
17545            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17546        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17547            let Some(locations) = references.await? else {
17548                return Ok(());
17549            };
17550
17551            if locations.is_empty() {
17552                // totally normal - the cursor may be on something which is not
17553                // a symbol (e.g. a keyword)
17554                log::info!("no references found under cursor");
17555                return Ok(());
17556            }
17557
17558            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17559
17560            let (locations, current_location_index) =
17561                multi_buffer.update(cx, |multi_buffer, cx| {
17562                    let mut locations = locations
17563                        .into_iter()
17564                        .filter_map(|loc| {
17565                            let start = multi_buffer.buffer_anchor_to_anchor(
17566                                &loc.buffer,
17567                                loc.range.start,
17568                                cx,
17569                            )?;
17570                            let end = multi_buffer.buffer_anchor_to_anchor(
17571                                &loc.buffer,
17572                                loc.range.end,
17573                                cx,
17574                            )?;
17575                            Some(start..end)
17576                        })
17577                        .collect::<Vec<_>>();
17578
17579                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17580                    // There is an O(n) implementation, but given this list will be
17581                    // small (usually <100 items), the extra O(log(n)) factor isn't
17582                    // worth the (surprisingly large amount of) extra complexity.
17583                    locations
17584                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17585
17586                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17587
17588                    let current_location_index = locations.iter().position(|loc| {
17589                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17590                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17591                    });
17592
17593                    (locations, current_location_index)
17594                })?;
17595
17596            let Some(current_location_index) = current_location_index else {
17597                // This indicates something has gone wrong, because we already
17598                // handle the "no references" case above
17599                log::error!(
17600                    "failed to find current reference under cursor. Total references: {}",
17601                    locations.len()
17602                );
17603                return Ok(());
17604            };
17605
17606            let destination_location_index = match direction {
17607                Direction::Next => (current_location_index + count) % locations.len(),
17608                Direction::Prev => {
17609                    (current_location_index + locations.len() - count % locations.len())
17610                        % locations.len()
17611                }
17612            };
17613
17614            // TODO(cameron): is this needed?
17615            // the thinking is to avoid "jumping to the current location" (avoid
17616            // polluting "jumplist" in vim terms)
17617            if current_location_index == destination_location_index {
17618                return Ok(());
17619            }
17620
17621            let Range { start, end } = locations[destination_location_index];
17622
17623            editor.update_in(cx, |editor, window, cx| {
17624                let effects = SelectionEffects::default();
17625
17626                editor.unfold_ranges(&[start..end], false, false, cx);
17627                editor.change_selections(effects, window, cx, |s| {
17628                    s.select_ranges([start..start]);
17629                });
17630            })?;
17631
17632            Ok(())
17633        }))
17634    }
17635
17636    pub fn find_all_references(
17637        &mut self,
17638        action: &FindAllReferences,
17639        window: &mut Window,
17640        cx: &mut Context<Self>,
17641    ) -> Option<Task<Result<Navigated>>> {
17642        let always_open_multibuffer = action.always_open_multibuffer;
17643        let selection = self.selections.newest_anchor();
17644        let multi_buffer = self.buffer.read(cx);
17645        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17646        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17647        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17648        let head = selection_offset.head();
17649
17650        let head_anchor = multi_buffer_snapshot.anchor_at(
17651            head,
17652            if head < selection_offset.tail() {
17653                Bias::Right
17654            } else {
17655                Bias::Left
17656            },
17657        );
17658
17659        match self
17660            .find_all_references_task_sources
17661            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17662        {
17663            Ok(_) => {
17664                log::info!(
17665                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17666                );
17667                return None;
17668            }
17669            Err(i) => {
17670                self.find_all_references_task_sources.insert(i, head_anchor);
17671            }
17672        }
17673
17674        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17675        let workspace = self.workspace()?;
17676        let project = workspace.read(cx).project().clone();
17677        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17678        Some(cx.spawn_in(window, async move |editor, cx| {
17679            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17680                if let Ok(i) = editor
17681                    .find_all_references_task_sources
17682                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17683                {
17684                    editor.find_all_references_task_sources.remove(i);
17685                }
17686            });
17687
17688            let Some(locations) = references.await? else {
17689                return anyhow::Ok(Navigated::No);
17690            };
17691            let mut locations = cx.update(|_, cx| {
17692                locations
17693                    .into_iter()
17694                    .map(|location| {
17695                        let buffer = location.buffer.read(cx);
17696                        (location.buffer, location.range.to_point(buffer))
17697                    })
17698                    // if special-casing the single-match case, remove ranges
17699                    // that intersect current selection
17700                    .filter(|(location_buffer, location)| {
17701                        if always_open_multibuffer || &buffer != location_buffer {
17702                            return true;
17703                        }
17704
17705                        !location.contains_inclusive(&selection_point.range())
17706                    })
17707                    .into_group_map()
17708            })?;
17709            if locations.is_empty() {
17710                return anyhow::Ok(Navigated::No);
17711            }
17712            for ranges in locations.values_mut() {
17713                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17714                ranges.dedup();
17715            }
17716            let mut num_locations = 0;
17717            for ranges in locations.values_mut() {
17718                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17719                ranges.dedup();
17720                num_locations += ranges.len();
17721            }
17722
17723            if num_locations == 1 && !always_open_multibuffer {
17724                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17725                let target_range = target_ranges.first().unwrap().clone();
17726
17727                return editor.update_in(cx, |editor, window, cx| {
17728                    let range = target_range.to_point(target_buffer.read(cx));
17729                    let range = editor.range_for_match(&range);
17730                    let range = range.start..range.start;
17731
17732                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17733                        editor.go_to_singleton_buffer_range(range, window, cx);
17734                    } else {
17735                        let pane = workspace.read(cx).active_pane().clone();
17736                        window.defer(cx, move |window, cx| {
17737                            let target_editor: Entity<Self> =
17738                                workspace.update(cx, |workspace, cx| {
17739                                    let pane = workspace.active_pane().clone();
17740
17741                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17742                                    let keep_old_preview = preview_tabs_settings
17743                                        .enable_keep_preview_on_code_navigation;
17744                                    let allow_new_preview = preview_tabs_settings
17745                                        .enable_preview_file_from_code_navigation;
17746
17747                                    workspace.open_project_item(
17748                                        pane,
17749                                        target_buffer.clone(),
17750                                        true,
17751                                        true,
17752                                        keep_old_preview,
17753                                        allow_new_preview,
17754                                        window,
17755                                        cx,
17756                                    )
17757                                });
17758                            target_editor.update(cx, |target_editor, cx| {
17759                                // When selecting a definition in a different buffer, disable the nav history
17760                                // to avoid creating a history entry at the previous cursor location.
17761                                pane.update(cx, |pane, _| pane.disable_history());
17762                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17763                                pane.update(cx, |pane, _| pane.enable_history());
17764                            });
17765                        });
17766                    }
17767                    Navigated::No
17768                });
17769            }
17770
17771            workspace.update_in(cx, |workspace, window, cx| {
17772                let target = locations
17773                    .iter()
17774                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17775                    .map(|(buffer, location)| {
17776                        buffer
17777                            .read(cx)
17778                            .text_for_range(location.clone())
17779                            .collect::<String>()
17780                    })
17781                    .filter(|text| !text.contains('\n'))
17782                    .unique()
17783                    .take(3)
17784                    .join(", ");
17785                let title = if target.is_empty() {
17786                    "References".to_owned()
17787                } else {
17788                    format!("References to {target}")
17789                };
17790                let allow_preview = PreviewTabsSettings::get_global(cx)
17791                    .enable_preview_multibuffer_from_code_navigation;
17792                Self::open_locations_in_multibuffer(
17793                    workspace,
17794                    locations,
17795                    title,
17796                    false,
17797                    allow_preview,
17798                    MultibufferSelectionMode::First,
17799                    window,
17800                    cx,
17801                );
17802                Navigated::Yes
17803            })
17804        }))
17805    }
17806
17807    /// Opens a multibuffer with the given project locations in it.
17808    pub fn open_locations_in_multibuffer(
17809        workspace: &mut Workspace,
17810        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17811        title: String,
17812        split: bool,
17813        allow_preview: bool,
17814        multibuffer_selection_mode: MultibufferSelectionMode,
17815        window: &mut Window,
17816        cx: &mut Context<Workspace>,
17817    ) {
17818        if locations.is_empty() {
17819            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17820            return;
17821        }
17822
17823        let capability = workspace.project().read(cx).capability();
17824        let mut ranges = <Vec<Range<Anchor>>>::new();
17825
17826        // a key to find existing multibuffer editors with the same set of locations
17827        // to prevent us from opening more and more multibuffer tabs for searches and the like
17828        let mut key = (title.clone(), vec![]);
17829        let excerpt_buffer = cx.new(|cx| {
17830            let key = &mut key.1;
17831            let mut multibuffer = MultiBuffer::new(capability);
17832            for (buffer, mut ranges_for_buffer) in locations {
17833                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17834                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17835                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17836                    PathKey::for_buffer(&buffer, cx),
17837                    buffer.clone(),
17838                    ranges_for_buffer,
17839                    multibuffer_context_lines(cx),
17840                    cx,
17841                );
17842                ranges.extend(new_ranges)
17843            }
17844
17845            multibuffer.with_title(title)
17846        });
17847        let existing = workspace.active_pane().update(cx, |pane, cx| {
17848            pane.items()
17849                .filter_map(|item| item.downcast::<Editor>())
17850                .find(|editor| {
17851                    editor
17852                        .read(cx)
17853                        .lookup_key
17854                        .as_ref()
17855                        .and_then(|it| {
17856                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17857                        })
17858                        .is_some_and(|it| *it == key)
17859                })
17860        });
17861        let was_existing = existing.is_some();
17862        let editor = existing.unwrap_or_else(|| {
17863            cx.new(|cx| {
17864                let mut editor = Editor::for_multibuffer(
17865                    excerpt_buffer,
17866                    Some(workspace.project().clone()),
17867                    window,
17868                    cx,
17869                );
17870                editor.lookup_key = Some(Box::new(key));
17871                editor
17872            })
17873        });
17874        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17875            MultibufferSelectionMode::First => {
17876                if let Some(first_range) = ranges.first() {
17877                    editor.change_selections(
17878                        SelectionEffects::no_scroll(),
17879                        window,
17880                        cx,
17881                        |selections| {
17882                            selections.clear_disjoint();
17883                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17884                        },
17885                    );
17886                }
17887                editor.highlight_background::<Self>(
17888                    &ranges,
17889                    |_, theme| theme.colors().editor_highlighted_line_background,
17890                    cx,
17891                );
17892            }
17893            MultibufferSelectionMode::All => {
17894                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17895                    selections.clear_disjoint();
17896                    selections.select_anchor_ranges(ranges);
17897                });
17898            }
17899        });
17900
17901        let item = Box::new(editor);
17902
17903        let pane = if split {
17904            workspace.adjacent_pane(window, cx)
17905        } else {
17906            workspace.active_pane().clone()
17907        };
17908        let activate_pane = split;
17909
17910        let mut destination_index = None;
17911        pane.update(cx, |pane, cx| {
17912            if allow_preview && !was_existing {
17913                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
17914            }
17915            if was_existing && !allow_preview {
17916                pane.unpreview_item_if_preview(item.item_id());
17917            }
17918            pane.add_item(item, activate_pane, true, destination_index, window, cx);
17919        });
17920    }
17921
17922    pub fn rename(
17923        &mut self,
17924        _: &Rename,
17925        window: &mut Window,
17926        cx: &mut Context<Self>,
17927    ) -> Option<Task<Result<()>>> {
17928        use language::ToOffset as _;
17929
17930        let provider = self.semantics_provider.clone()?;
17931        let selection = self.selections.newest_anchor().clone();
17932        let (cursor_buffer, cursor_buffer_position) = self
17933            .buffer
17934            .read(cx)
17935            .text_anchor_for_position(selection.head(), cx)?;
17936        let (tail_buffer, cursor_buffer_position_end) = self
17937            .buffer
17938            .read(cx)
17939            .text_anchor_for_position(selection.tail(), cx)?;
17940        if tail_buffer != cursor_buffer {
17941            return None;
17942        }
17943
17944        let snapshot = cursor_buffer.read(cx).snapshot();
17945        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17946        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17947        let prepare_rename = provider
17948            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17949            .unwrap_or_else(|| Task::ready(Ok(None)));
17950        drop(snapshot);
17951
17952        Some(cx.spawn_in(window, async move |this, cx| {
17953            let rename_range = if let Some(range) = prepare_rename.await? {
17954                Some(range)
17955            } else {
17956                this.update(cx, |this, cx| {
17957                    let buffer = this.buffer.read(cx).snapshot(cx);
17958                    let mut buffer_highlights = this
17959                        .document_highlights_for_position(selection.head(), &buffer)
17960                        .filter(|highlight| {
17961                            highlight.start.excerpt_id == selection.head().excerpt_id
17962                                && highlight.end.excerpt_id == selection.head().excerpt_id
17963                        });
17964                    buffer_highlights
17965                        .next()
17966                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17967                })?
17968            };
17969            if let Some(rename_range) = rename_range {
17970                this.update_in(cx, |this, window, cx| {
17971                    let snapshot = cursor_buffer.read(cx).snapshot();
17972                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17973                    let cursor_offset_in_rename_range =
17974                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17975                    let cursor_offset_in_rename_range_end =
17976                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17977
17978                    this.take_rename(false, window, cx);
17979                    let buffer = this.buffer.read(cx).read(cx);
17980                    let cursor_offset = selection.head().to_offset(&buffer);
17981                    let rename_start =
17982                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17983                    let rename_end = rename_start + rename_buffer_range.len();
17984                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17985                    let mut old_highlight_id = None;
17986                    let old_name: Arc<str> = buffer
17987                        .chunks(rename_start..rename_end, true)
17988                        .map(|chunk| {
17989                            if old_highlight_id.is_none() {
17990                                old_highlight_id = chunk.syntax_highlight_id;
17991                            }
17992                            chunk.text
17993                        })
17994                        .collect::<String>()
17995                        .into();
17996
17997                    drop(buffer);
17998
17999                    // Position the selection in the rename editor so that it matches the current selection.
18000                    this.show_local_selections = false;
18001                    let rename_editor = cx.new(|cx| {
18002                        let mut editor = Editor::single_line(window, cx);
18003                        editor.buffer.update(cx, |buffer, cx| {
18004                            buffer.edit(
18005                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18006                                None,
18007                                cx,
18008                            )
18009                        });
18010                        let cursor_offset_in_rename_range =
18011                            MultiBufferOffset(cursor_offset_in_rename_range);
18012                        let cursor_offset_in_rename_range_end =
18013                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18014                        let rename_selection_range = match cursor_offset_in_rename_range
18015                            .cmp(&cursor_offset_in_rename_range_end)
18016                        {
18017                            Ordering::Equal => {
18018                                editor.select_all(&SelectAll, window, cx);
18019                                return editor;
18020                            }
18021                            Ordering::Less => {
18022                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18023                            }
18024                            Ordering::Greater => {
18025                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18026                            }
18027                        };
18028                        if rename_selection_range.end.0 > old_name.len() {
18029                            editor.select_all(&SelectAll, window, cx);
18030                        } else {
18031                            editor.change_selections(Default::default(), window, cx, |s| {
18032                                s.select_ranges([rename_selection_range]);
18033                            });
18034                        }
18035                        editor
18036                    });
18037                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18038                        if e == &EditorEvent::Focused {
18039                            cx.emit(EditorEvent::FocusedIn)
18040                        }
18041                    })
18042                    .detach();
18043
18044                    let write_highlights =
18045                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18046                    let read_highlights =
18047                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18048                    let ranges = write_highlights
18049                        .iter()
18050                        .flat_map(|(_, ranges)| ranges.iter())
18051                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18052                        .cloned()
18053                        .collect();
18054
18055                    this.highlight_text::<Rename>(
18056                        ranges,
18057                        HighlightStyle {
18058                            fade_out: Some(0.6),
18059                            ..Default::default()
18060                        },
18061                        cx,
18062                    );
18063                    let rename_focus_handle = rename_editor.focus_handle(cx);
18064                    window.focus(&rename_focus_handle, cx);
18065                    let block_id = this.insert_blocks(
18066                        [BlockProperties {
18067                            style: BlockStyle::Flex,
18068                            placement: BlockPlacement::Below(range.start),
18069                            height: Some(1),
18070                            render: Arc::new({
18071                                let rename_editor = rename_editor.clone();
18072                                move |cx: &mut BlockContext| {
18073                                    let mut text_style = cx.editor_style.text.clone();
18074                                    if let Some(highlight_style) = old_highlight_id
18075                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18076                                    {
18077                                        text_style = text_style.highlight(highlight_style);
18078                                    }
18079                                    div()
18080                                        .block_mouse_except_scroll()
18081                                        .pl(cx.anchor_x)
18082                                        .child(EditorElement::new(
18083                                            &rename_editor,
18084                                            EditorStyle {
18085                                                background: cx.theme().system().transparent,
18086                                                local_player: cx.editor_style.local_player,
18087                                                text: text_style,
18088                                                scrollbar_width: cx.editor_style.scrollbar_width,
18089                                                syntax: cx.editor_style.syntax.clone(),
18090                                                status: cx.editor_style.status.clone(),
18091                                                inlay_hints_style: HighlightStyle {
18092                                                    font_weight: Some(FontWeight::BOLD),
18093                                                    ..make_inlay_hints_style(cx.app)
18094                                                },
18095                                                edit_prediction_styles: make_suggestion_styles(
18096                                                    cx.app,
18097                                                ),
18098                                                ..EditorStyle::default()
18099                                            },
18100                                        ))
18101                                        .into_any_element()
18102                                }
18103                            }),
18104                            priority: 0,
18105                        }],
18106                        Some(Autoscroll::fit()),
18107                        cx,
18108                    )[0];
18109                    this.pending_rename = Some(RenameState {
18110                        range,
18111                        old_name,
18112                        editor: rename_editor,
18113                        block_id,
18114                    });
18115                })?;
18116            }
18117
18118            Ok(())
18119        }))
18120    }
18121
18122    pub fn confirm_rename(
18123        &mut self,
18124        _: &ConfirmRename,
18125        window: &mut Window,
18126        cx: &mut Context<Self>,
18127    ) -> Option<Task<Result<()>>> {
18128        let rename = self.take_rename(false, window, cx)?;
18129        let workspace = self.workspace()?.downgrade();
18130        let (buffer, start) = self
18131            .buffer
18132            .read(cx)
18133            .text_anchor_for_position(rename.range.start, cx)?;
18134        let (end_buffer, _) = self
18135            .buffer
18136            .read(cx)
18137            .text_anchor_for_position(rename.range.end, cx)?;
18138        if buffer != end_buffer {
18139            return None;
18140        }
18141
18142        let old_name = rename.old_name;
18143        let new_name = rename.editor.read(cx).text(cx);
18144
18145        let rename = self.semantics_provider.as_ref()?.perform_rename(
18146            &buffer,
18147            start,
18148            new_name.clone(),
18149            cx,
18150        )?;
18151
18152        Some(cx.spawn_in(window, async move |editor, cx| {
18153            let project_transaction = rename.await?;
18154            Self::open_project_transaction(
18155                &editor,
18156                workspace,
18157                project_transaction,
18158                format!("Rename: {}{}", old_name, new_name),
18159                cx,
18160            )
18161            .await?;
18162
18163            editor.update(cx, |editor, cx| {
18164                editor.refresh_document_highlights(cx);
18165            })?;
18166            Ok(())
18167        }))
18168    }
18169
18170    fn take_rename(
18171        &mut self,
18172        moving_cursor: bool,
18173        window: &mut Window,
18174        cx: &mut Context<Self>,
18175    ) -> Option<RenameState> {
18176        let rename = self.pending_rename.take()?;
18177        if rename.editor.focus_handle(cx).is_focused(window) {
18178            window.focus(&self.focus_handle, cx);
18179        }
18180
18181        self.remove_blocks(
18182            [rename.block_id].into_iter().collect(),
18183            Some(Autoscroll::fit()),
18184            cx,
18185        );
18186        self.clear_highlights::<Rename>(cx);
18187        self.show_local_selections = true;
18188
18189        if moving_cursor {
18190            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18191                editor
18192                    .selections
18193                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18194                    .head()
18195            });
18196
18197            // Update the selection to match the position of the selection inside
18198            // the rename editor.
18199            let snapshot = self.buffer.read(cx).read(cx);
18200            let rename_range = rename.range.to_offset(&snapshot);
18201            let cursor_in_editor = snapshot
18202                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18203                .min(rename_range.end);
18204            drop(snapshot);
18205
18206            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18207                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18208            });
18209        } else {
18210            self.refresh_document_highlights(cx);
18211        }
18212
18213        Some(rename)
18214    }
18215
18216    pub fn pending_rename(&self) -> Option<&RenameState> {
18217        self.pending_rename.as_ref()
18218    }
18219
18220    fn format(
18221        &mut self,
18222        _: &Format,
18223        window: &mut Window,
18224        cx: &mut Context<Self>,
18225    ) -> Option<Task<Result<()>>> {
18226        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18227
18228        let project = match &self.project {
18229            Some(project) => project.clone(),
18230            None => return None,
18231        };
18232
18233        Some(self.perform_format(
18234            project,
18235            FormatTrigger::Manual,
18236            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18237            window,
18238            cx,
18239        ))
18240    }
18241
18242    fn format_selections(
18243        &mut self,
18244        _: &FormatSelections,
18245        window: &mut Window,
18246        cx: &mut Context<Self>,
18247    ) -> Option<Task<Result<()>>> {
18248        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18249
18250        let project = match &self.project {
18251            Some(project) => project.clone(),
18252            None => return None,
18253        };
18254
18255        let ranges = self
18256            .selections
18257            .all_adjusted(&self.display_snapshot(cx))
18258            .into_iter()
18259            .map(|selection| selection.range())
18260            .collect_vec();
18261
18262        Some(self.perform_format(
18263            project,
18264            FormatTrigger::Manual,
18265            FormatTarget::Ranges(ranges),
18266            window,
18267            cx,
18268        ))
18269    }
18270
18271    fn perform_format(
18272        &mut self,
18273        project: Entity<Project>,
18274        trigger: FormatTrigger,
18275        target: FormatTarget,
18276        window: &mut Window,
18277        cx: &mut Context<Self>,
18278    ) -> Task<Result<()>> {
18279        let buffer = self.buffer.clone();
18280        let (buffers, target) = match target {
18281            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18282            FormatTarget::Ranges(selection_ranges) => {
18283                let multi_buffer = buffer.read(cx);
18284                let snapshot = multi_buffer.read(cx);
18285                let mut buffers = HashSet::default();
18286                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18287                    BTreeMap::new();
18288                for selection_range in selection_ranges {
18289                    for (buffer, buffer_range, _) in
18290                        snapshot.range_to_buffer_ranges(selection_range)
18291                    {
18292                        let buffer_id = buffer.remote_id();
18293                        let start = buffer.anchor_before(buffer_range.start);
18294                        let end = buffer.anchor_after(buffer_range.end);
18295                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18296                        buffer_id_to_ranges
18297                            .entry(buffer_id)
18298                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18299                            .or_insert_with(|| vec![start..end]);
18300                    }
18301                }
18302                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18303            }
18304        };
18305
18306        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18307        let selections_prev = transaction_id_prev
18308            .and_then(|transaction_id_prev| {
18309                // default to selections as they were after the last edit, if we have them,
18310                // instead of how they are now.
18311                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18312                // will take you back to where you made the last edit, instead of staying where you scrolled
18313                self.selection_history
18314                    .transaction(transaction_id_prev)
18315                    .map(|t| t.0.clone())
18316            })
18317            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18318
18319        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18320        let format = project.update(cx, |project, cx| {
18321            project.format(buffers, target, true, trigger, cx)
18322        });
18323
18324        cx.spawn_in(window, async move |editor, cx| {
18325            let transaction = futures::select_biased! {
18326                transaction = format.log_err().fuse() => transaction,
18327                () = timeout => {
18328                    log::warn!("timed out waiting for formatting");
18329                    None
18330                }
18331            };
18332
18333            buffer
18334                .update(cx, |buffer, cx| {
18335                    if let Some(transaction) = transaction
18336                        && !buffer.is_singleton()
18337                    {
18338                        buffer.push_transaction(&transaction.0, cx);
18339                    }
18340                    cx.notify();
18341                })
18342                .ok();
18343
18344            if let Some(transaction_id_now) =
18345                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18346            {
18347                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18348                if has_new_transaction {
18349                    _ = editor.update(cx, |editor, _| {
18350                        editor
18351                            .selection_history
18352                            .insert_transaction(transaction_id_now, selections_prev);
18353                    });
18354                }
18355            }
18356
18357            Ok(())
18358        })
18359    }
18360
18361    fn organize_imports(
18362        &mut self,
18363        _: &OrganizeImports,
18364        window: &mut Window,
18365        cx: &mut Context<Self>,
18366    ) -> Option<Task<Result<()>>> {
18367        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18368        let project = match &self.project {
18369            Some(project) => project.clone(),
18370            None => return None,
18371        };
18372        Some(self.perform_code_action_kind(
18373            project,
18374            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18375            window,
18376            cx,
18377        ))
18378    }
18379
18380    fn perform_code_action_kind(
18381        &mut self,
18382        project: Entity<Project>,
18383        kind: CodeActionKind,
18384        window: &mut Window,
18385        cx: &mut Context<Self>,
18386    ) -> Task<Result<()>> {
18387        let buffer = self.buffer.clone();
18388        let buffers = buffer.read(cx).all_buffers();
18389        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18390        let apply_action = project.update(cx, |project, cx| {
18391            project.apply_code_action_kind(buffers, kind, true, cx)
18392        });
18393        cx.spawn_in(window, async move |_, cx| {
18394            let transaction = futures::select_biased! {
18395                () = timeout => {
18396                    log::warn!("timed out waiting for executing code action");
18397                    None
18398                }
18399                transaction = apply_action.log_err().fuse() => transaction,
18400            };
18401            buffer
18402                .update(cx, |buffer, cx| {
18403                    // check if we need this
18404                    if let Some(transaction) = transaction
18405                        && !buffer.is_singleton()
18406                    {
18407                        buffer.push_transaction(&transaction.0, cx);
18408                    }
18409                    cx.notify();
18410                })
18411                .ok();
18412            Ok(())
18413        })
18414    }
18415
18416    pub fn restart_language_server(
18417        &mut self,
18418        _: &RestartLanguageServer,
18419        _: &mut Window,
18420        cx: &mut Context<Self>,
18421    ) {
18422        if let Some(project) = self.project.clone() {
18423            self.buffer.update(cx, |multi_buffer, cx| {
18424                project.update(cx, |project, cx| {
18425                    project.restart_language_servers_for_buffers(
18426                        multi_buffer.all_buffers().into_iter().collect(),
18427                        HashSet::default(),
18428                        cx,
18429                    );
18430                });
18431            })
18432        }
18433    }
18434
18435    pub fn stop_language_server(
18436        &mut self,
18437        _: &StopLanguageServer,
18438        _: &mut Window,
18439        cx: &mut Context<Self>,
18440    ) {
18441        if let Some(project) = self.project.clone() {
18442            self.buffer.update(cx, |multi_buffer, cx| {
18443                project.update(cx, |project, cx| {
18444                    project.stop_language_servers_for_buffers(
18445                        multi_buffer.all_buffers().into_iter().collect(),
18446                        HashSet::default(),
18447                        cx,
18448                    );
18449                });
18450            });
18451            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18452        }
18453    }
18454
18455    fn cancel_language_server_work(
18456        workspace: &mut Workspace,
18457        _: &actions::CancelLanguageServerWork,
18458        _: &mut Window,
18459        cx: &mut Context<Workspace>,
18460    ) {
18461        let project = workspace.project();
18462        let buffers = workspace
18463            .active_item(cx)
18464            .and_then(|item| item.act_as::<Editor>(cx))
18465            .map_or(HashSet::default(), |editor| {
18466                editor.read(cx).buffer.read(cx).all_buffers()
18467            });
18468        project.update(cx, |project, cx| {
18469            project.cancel_language_server_work_for_buffers(buffers, cx);
18470        });
18471    }
18472
18473    fn show_character_palette(
18474        &mut self,
18475        _: &ShowCharacterPalette,
18476        window: &mut Window,
18477        _: &mut Context<Self>,
18478    ) {
18479        window.show_character_palette();
18480    }
18481
18482    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18483        if !self.diagnostics_enabled() {
18484            return;
18485        }
18486
18487        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18488            let buffer = self.buffer.read(cx).snapshot(cx);
18489            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18490            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18491            let is_valid = buffer
18492                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18493                .any(|entry| {
18494                    entry.diagnostic.is_primary
18495                        && !entry.range.is_empty()
18496                        && entry.range.start == primary_range_start
18497                        && entry.diagnostic.message == active_diagnostics.active_message
18498                });
18499
18500            if !is_valid {
18501                self.dismiss_diagnostics(cx);
18502            }
18503        }
18504    }
18505
18506    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18507        match &self.active_diagnostics {
18508            ActiveDiagnostic::Group(group) => Some(group),
18509            _ => None,
18510        }
18511    }
18512
18513    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18514        if !self.diagnostics_enabled() {
18515            return;
18516        }
18517        self.dismiss_diagnostics(cx);
18518        self.active_diagnostics = ActiveDiagnostic::All;
18519    }
18520
18521    fn activate_diagnostics(
18522        &mut self,
18523        buffer_id: BufferId,
18524        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18525        window: &mut Window,
18526        cx: &mut Context<Self>,
18527    ) {
18528        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18529            return;
18530        }
18531        self.dismiss_diagnostics(cx);
18532        let snapshot = self.snapshot(window, cx);
18533        let buffer = self.buffer.read(cx).snapshot(cx);
18534        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18535            return;
18536        };
18537
18538        let diagnostic_group = buffer
18539            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18540            .collect::<Vec<_>>();
18541
18542        let language_registry = self
18543            .project()
18544            .map(|project| project.read(cx).languages().clone());
18545
18546        let blocks = renderer.render_group(
18547            diagnostic_group,
18548            buffer_id,
18549            snapshot,
18550            cx.weak_entity(),
18551            language_registry,
18552            cx,
18553        );
18554
18555        let blocks = self.display_map.update(cx, |display_map, cx| {
18556            display_map.insert_blocks(blocks, cx).into_iter().collect()
18557        });
18558        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18559            active_range: buffer.anchor_before(diagnostic.range.start)
18560                ..buffer.anchor_after(diagnostic.range.end),
18561            active_message: diagnostic.diagnostic.message.clone(),
18562            group_id: diagnostic.diagnostic.group_id,
18563            blocks,
18564        });
18565        cx.notify();
18566    }
18567
18568    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18569        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18570            return;
18571        };
18572
18573        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18574        if let ActiveDiagnostic::Group(group) = prev {
18575            self.display_map.update(cx, |display_map, cx| {
18576                display_map.remove_blocks(group.blocks, cx);
18577            });
18578            cx.notify();
18579        }
18580    }
18581
18582    /// Disable inline diagnostics rendering for this editor.
18583    pub fn disable_inline_diagnostics(&mut self) {
18584        self.inline_diagnostics_enabled = false;
18585        self.inline_diagnostics_update = Task::ready(());
18586        self.inline_diagnostics.clear();
18587    }
18588
18589    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18590        self.diagnostics_enabled = false;
18591        self.dismiss_diagnostics(cx);
18592        self.inline_diagnostics_update = Task::ready(());
18593        self.inline_diagnostics.clear();
18594    }
18595
18596    pub fn disable_word_completions(&mut self) {
18597        self.word_completions_enabled = false;
18598    }
18599
18600    pub fn diagnostics_enabled(&self) -> bool {
18601        self.diagnostics_enabled && self.mode.is_full()
18602    }
18603
18604    pub fn inline_diagnostics_enabled(&self) -> bool {
18605        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18606    }
18607
18608    pub fn show_inline_diagnostics(&self) -> bool {
18609        self.show_inline_diagnostics
18610    }
18611
18612    pub fn toggle_inline_diagnostics(
18613        &mut self,
18614        _: &ToggleInlineDiagnostics,
18615        window: &mut Window,
18616        cx: &mut Context<Editor>,
18617    ) {
18618        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18619        self.refresh_inline_diagnostics(false, window, cx);
18620    }
18621
18622    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18623        self.diagnostics_max_severity = severity;
18624        self.display_map.update(cx, |display_map, _| {
18625            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18626        });
18627    }
18628
18629    pub fn toggle_diagnostics(
18630        &mut self,
18631        _: &ToggleDiagnostics,
18632        window: &mut Window,
18633        cx: &mut Context<Editor>,
18634    ) {
18635        if !self.diagnostics_enabled() {
18636            return;
18637        }
18638
18639        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18640            EditorSettings::get_global(cx)
18641                .diagnostics_max_severity
18642                .filter(|severity| severity != &DiagnosticSeverity::Off)
18643                .unwrap_or(DiagnosticSeverity::Hint)
18644        } else {
18645            DiagnosticSeverity::Off
18646        };
18647        self.set_max_diagnostics_severity(new_severity, cx);
18648        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18649            self.active_diagnostics = ActiveDiagnostic::None;
18650            self.inline_diagnostics_update = Task::ready(());
18651            self.inline_diagnostics.clear();
18652        } else {
18653            self.refresh_inline_diagnostics(false, window, cx);
18654        }
18655
18656        cx.notify();
18657    }
18658
18659    pub fn toggle_minimap(
18660        &mut self,
18661        _: &ToggleMinimap,
18662        window: &mut Window,
18663        cx: &mut Context<Editor>,
18664    ) {
18665        if self.supports_minimap(cx) {
18666            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18667        }
18668    }
18669
18670    fn refresh_inline_diagnostics(
18671        &mut self,
18672        debounce: bool,
18673        window: &mut Window,
18674        cx: &mut Context<Self>,
18675    ) {
18676        let max_severity = ProjectSettings::get_global(cx)
18677            .diagnostics
18678            .inline
18679            .max_severity
18680            .unwrap_or(self.diagnostics_max_severity);
18681
18682        if !self.inline_diagnostics_enabled()
18683            || !self.diagnostics_enabled()
18684            || !self.show_inline_diagnostics
18685            || max_severity == DiagnosticSeverity::Off
18686        {
18687            self.inline_diagnostics_update = Task::ready(());
18688            self.inline_diagnostics.clear();
18689            return;
18690        }
18691
18692        let debounce_ms = ProjectSettings::get_global(cx)
18693            .diagnostics
18694            .inline
18695            .update_debounce_ms;
18696        let debounce = if debounce && debounce_ms > 0 {
18697            Some(Duration::from_millis(debounce_ms))
18698        } else {
18699            None
18700        };
18701        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18702            if let Some(debounce) = debounce {
18703                cx.background_executor().timer(debounce).await;
18704            }
18705            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18706                editor
18707                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18708                    .ok()
18709            }) else {
18710                return;
18711            };
18712
18713            let new_inline_diagnostics = cx
18714                .background_spawn(async move {
18715                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18716                    for diagnostic_entry in
18717                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18718                    {
18719                        let message = diagnostic_entry
18720                            .diagnostic
18721                            .message
18722                            .split_once('\n')
18723                            .map(|(line, _)| line)
18724                            .map(SharedString::new)
18725                            .unwrap_or_else(|| {
18726                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18727                            });
18728                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18729                        let (Ok(i) | Err(i)) = inline_diagnostics
18730                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18731                        inline_diagnostics.insert(
18732                            i,
18733                            (
18734                                start_anchor,
18735                                InlineDiagnostic {
18736                                    message,
18737                                    group_id: diagnostic_entry.diagnostic.group_id,
18738                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18739                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18740                                    severity: diagnostic_entry.diagnostic.severity,
18741                                },
18742                            ),
18743                        );
18744                    }
18745                    inline_diagnostics
18746                })
18747                .await;
18748
18749            editor
18750                .update(cx, |editor, cx| {
18751                    editor.inline_diagnostics = new_inline_diagnostics;
18752                    cx.notify();
18753                })
18754                .ok();
18755        });
18756    }
18757
18758    fn pull_diagnostics(
18759        &mut self,
18760        buffer_id: Option<BufferId>,
18761        window: &Window,
18762        cx: &mut Context<Self>,
18763    ) -> Option<()> {
18764        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18765            return None;
18766        }
18767        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18768            .diagnostics
18769            .lsp_pull_diagnostics;
18770        if !pull_diagnostics_settings.enabled {
18771            return None;
18772        }
18773        let project = self.project()?.downgrade();
18774
18775        let mut edited_buffer_ids = HashSet::default();
18776        let mut edited_worktree_ids = HashSet::default();
18777        let edited_buffers = match buffer_id {
18778            Some(buffer_id) => {
18779                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18780                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18781                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18782                edited_worktree_ids.insert(worktree_id);
18783                vec![buffer]
18784            }
18785            None => self
18786                .buffer()
18787                .read(cx)
18788                .all_buffers()
18789                .into_iter()
18790                .filter(|buffer| {
18791                    let buffer = buffer.read(cx);
18792                    match buffer.file().map(|f| f.worktree_id(cx)) {
18793                        Some(worktree_id) => {
18794                            edited_buffer_ids.insert(buffer.remote_id());
18795                            edited_worktree_ids.insert(worktree_id);
18796                            true
18797                        }
18798                        None => false,
18799                    }
18800                })
18801                .collect::<Vec<_>>(),
18802        };
18803
18804        if edited_buffers.is_empty() {
18805            self.pull_diagnostics_task = Task::ready(());
18806            self.pull_diagnostics_background_task = Task::ready(());
18807            return None;
18808        }
18809
18810        let mut already_used_buffers = HashSet::default();
18811        let related_open_buffers = self
18812            .workspace
18813            .as_ref()
18814            .and_then(|(workspace, _)| workspace.upgrade())
18815            .into_iter()
18816            .flat_map(|workspace| workspace.read(cx).panes())
18817            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18818            .filter(|editor| editor != &cx.entity())
18819            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18820            .filter(|buffer| {
18821                let buffer = buffer.read(cx);
18822                let buffer_id = buffer.remote_id();
18823                if already_used_buffers.insert(buffer_id) {
18824                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18825                        return !edited_buffer_ids.contains(&buffer_id)
18826                            && !edited_worktree_ids.contains(&worktree_id);
18827                    }
18828                }
18829                false
18830            })
18831            .collect::<Vec<_>>();
18832
18833        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18834        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18835            if buffers.is_empty() {
18836                return Task::ready(());
18837            }
18838            let project_weak = project.clone();
18839            cx.spawn_in(window, async move |_, cx| {
18840                cx.background_executor().timer(delay).await;
18841
18842                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18843                    buffers
18844                        .into_iter()
18845                        .filter_map(|buffer| {
18846                            project_weak
18847                                .update(cx, |project, cx| {
18848                                    project.lsp_store().update(cx, |lsp_store, cx| {
18849                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18850                                    })
18851                                })
18852                                .ok()
18853                        })
18854                        .collect::<FuturesUnordered<_>>()
18855                }) else {
18856                    return;
18857                };
18858
18859                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18860                    if let Err(e) = pull_task {
18861                        log::error!("Failed to update project diagnostics: {e:#}");
18862                    }
18863                }
18864            })
18865        };
18866
18867        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18868        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18869
18870        Some(())
18871    }
18872
18873    pub fn set_selections_from_remote(
18874        &mut self,
18875        selections: Vec<Selection<Anchor>>,
18876        pending_selection: Option<Selection<Anchor>>,
18877        window: &mut Window,
18878        cx: &mut Context<Self>,
18879    ) {
18880        let old_cursor_position = self.selections.newest_anchor().head();
18881        self.selections
18882            .change_with(&self.display_snapshot(cx), |s| {
18883                s.select_anchors(selections);
18884                if let Some(pending_selection) = pending_selection {
18885                    s.set_pending(pending_selection, SelectMode::Character);
18886                } else {
18887                    s.clear_pending();
18888                }
18889            });
18890        self.selections_did_change(
18891            false,
18892            &old_cursor_position,
18893            SelectionEffects::default(),
18894            window,
18895            cx,
18896        );
18897    }
18898
18899    pub fn transact(
18900        &mut self,
18901        window: &mut Window,
18902        cx: &mut Context<Self>,
18903        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18904    ) -> Option<TransactionId> {
18905        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18906            this.start_transaction_at(Instant::now(), window, cx);
18907            update(this, window, cx);
18908            this.end_transaction_at(Instant::now(), cx)
18909        })
18910    }
18911
18912    pub fn start_transaction_at(
18913        &mut self,
18914        now: Instant,
18915        window: &mut Window,
18916        cx: &mut Context<Self>,
18917    ) -> Option<TransactionId> {
18918        self.end_selection(window, cx);
18919        if let Some(tx_id) = self
18920            .buffer
18921            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18922        {
18923            self.selection_history
18924                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18925            cx.emit(EditorEvent::TransactionBegun {
18926                transaction_id: tx_id,
18927            });
18928            Some(tx_id)
18929        } else {
18930            None
18931        }
18932    }
18933
18934    pub fn end_transaction_at(
18935        &mut self,
18936        now: Instant,
18937        cx: &mut Context<Self>,
18938    ) -> Option<TransactionId> {
18939        if let Some(transaction_id) = self
18940            .buffer
18941            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18942        {
18943            if let Some((_, end_selections)) =
18944                self.selection_history.transaction_mut(transaction_id)
18945            {
18946                *end_selections = Some(self.selections.disjoint_anchors_arc());
18947            } else {
18948                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18949            }
18950
18951            cx.emit(EditorEvent::Edited { transaction_id });
18952            Some(transaction_id)
18953        } else {
18954            None
18955        }
18956    }
18957
18958    pub fn modify_transaction_selection_history(
18959        &mut self,
18960        transaction_id: TransactionId,
18961        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18962    ) -> bool {
18963        self.selection_history
18964            .transaction_mut(transaction_id)
18965            .map(modify)
18966            .is_some()
18967    }
18968
18969    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18970        if self.selection_mark_mode {
18971            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18972                s.move_with(|_, sel| {
18973                    sel.collapse_to(sel.head(), SelectionGoal::None);
18974                });
18975            })
18976        }
18977        self.selection_mark_mode = true;
18978        cx.notify();
18979    }
18980
18981    pub fn swap_selection_ends(
18982        &mut self,
18983        _: &actions::SwapSelectionEnds,
18984        window: &mut Window,
18985        cx: &mut Context<Self>,
18986    ) {
18987        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18988            s.move_with(|_, sel| {
18989                if sel.start != sel.end {
18990                    sel.reversed = !sel.reversed
18991                }
18992            });
18993        });
18994        self.request_autoscroll(Autoscroll::newest(), cx);
18995        cx.notify();
18996    }
18997
18998    pub fn toggle_focus(
18999        workspace: &mut Workspace,
19000        _: &actions::ToggleFocus,
19001        window: &mut Window,
19002        cx: &mut Context<Workspace>,
19003    ) {
19004        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19005            return;
19006        };
19007        workspace.activate_item(&item, true, true, window, cx);
19008    }
19009
19010    pub fn toggle_fold(
19011        &mut self,
19012        _: &actions::ToggleFold,
19013        window: &mut Window,
19014        cx: &mut Context<Self>,
19015    ) {
19016        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19017            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19018            let selection = self.selections.newest::<Point>(&display_map);
19019
19020            let range = if selection.is_empty() {
19021                let point = selection.head().to_display_point(&display_map);
19022                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19023                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19024                    .to_point(&display_map);
19025                start..end
19026            } else {
19027                selection.range()
19028            };
19029            if display_map.folds_in_range(range).next().is_some() {
19030                self.unfold_lines(&Default::default(), window, cx)
19031            } else {
19032                self.fold(&Default::default(), window, cx)
19033            }
19034        } else {
19035            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19036            let buffer_ids: HashSet<_> = self
19037                .selections
19038                .disjoint_anchor_ranges()
19039                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19040                .collect();
19041
19042            let should_unfold = buffer_ids
19043                .iter()
19044                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19045
19046            for buffer_id in buffer_ids {
19047                if should_unfold {
19048                    self.unfold_buffer(buffer_id, cx);
19049                } else {
19050                    self.fold_buffer(buffer_id, cx);
19051                }
19052            }
19053        }
19054    }
19055
19056    pub fn toggle_fold_recursive(
19057        &mut self,
19058        _: &actions::ToggleFoldRecursive,
19059        window: &mut Window,
19060        cx: &mut Context<Self>,
19061    ) {
19062        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19063
19064        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19065        let range = if selection.is_empty() {
19066            let point = selection.head().to_display_point(&display_map);
19067            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19068            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19069                .to_point(&display_map);
19070            start..end
19071        } else {
19072            selection.range()
19073        };
19074        if display_map.folds_in_range(range).next().is_some() {
19075            self.unfold_recursive(&Default::default(), window, cx)
19076        } else {
19077            self.fold_recursive(&Default::default(), window, cx)
19078        }
19079    }
19080
19081    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19082        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19083            let mut to_fold = Vec::new();
19084            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19085            let selections = self.selections.all_adjusted(&display_map);
19086
19087            for selection in selections {
19088                let range = selection.range().sorted();
19089                let buffer_start_row = range.start.row;
19090
19091                if range.start.row != range.end.row {
19092                    let mut found = false;
19093                    let mut row = range.start.row;
19094                    while row <= range.end.row {
19095                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19096                        {
19097                            found = true;
19098                            row = crease.range().end.row + 1;
19099                            to_fold.push(crease);
19100                        } else {
19101                            row += 1
19102                        }
19103                    }
19104                    if found {
19105                        continue;
19106                    }
19107                }
19108
19109                for row in (0..=range.start.row).rev() {
19110                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19111                        && crease.range().end.row >= buffer_start_row
19112                    {
19113                        to_fold.push(crease);
19114                        if row <= range.start.row {
19115                            break;
19116                        }
19117                    }
19118                }
19119            }
19120
19121            self.fold_creases(to_fold, true, window, cx);
19122        } else {
19123            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19124            let buffer_ids = self
19125                .selections
19126                .disjoint_anchor_ranges()
19127                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19128                .collect::<HashSet<_>>();
19129            for buffer_id in buffer_ids {
19130                self.fold_buffer(buffer_id, cx);
19131            }
19132        }
19133    }
19134
19135    pub fn toggle_fold_all(
19136        &mut self,
19137        _: &actions::ToggleFoldAll,
19138        window: &mut Window,
19139        cx: &mut Context<Self>,
19140    ) {
19141        let has_folds = if self.buffer.read(cx).is_singleton() {
19142            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19143            let has_folds = display_map
19144                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19145                .next()
19146                .is_some();
19147            has_folds
19148        } else {
19149            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19150            let has_folds = buffer_ids
19151                .iter()
19152                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19153            has_folds
19154        };
19155
19156        if has_folds {
19157            self.unfold_all(&actions::UnfoldAll, window, cx);
19158        } else {
19159            self.fold_all(&actions::FoldAll, window, cx);
19160        }
19161    }
19162
19163    fn fold_at_level(
19164        &mut self,
19165        fold_at: &FoldAtLevel,
19166        window: &mut Window,
19167        cx: &mut Context<Self>,
19168    ) {
19169        if !self.buffer.read(cx).is_singleton() {
19170            return;
19171        }
19172
19173        let fold_at_level = fold_at.0;
19174        let snapshot = self.buffer.read(cx).snapshot(cx);
19175        let mut to_fold = Vec::new();
19176        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19177
19178        let row_ranges_to_keep: Vec<Range<u32>> = self
19179            .selections
19180            .all::<Point>(&self.display_snapshot(cx))
19181            .into_iter()
19182            .map(|sel| sel.start.row..sel.end.row)
19183            .collect();
19184
19185        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19186            while start_row < end_row {
19187                match self
19188                    .snapshot(window, cx)
19189                    .crease_for_buffer_row(MultiBufferRow(start_row))
19190                {
19191                    Some(crease) => {
19192                        let nested_start_row = crease.range().start.row + 1;
19193                        let nested_end_row = crease.range().end.row;
19194
19195                        if current_level < fold_at_level {
19196                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19197                        } else if current_level == fold_at_level {
19198                            // Fold iff there is no selection completely contained within the fold region
19199                            if !row_ranges_to_keep.iter().any(|selection| {
19200                                selection.end >= nested_start_row
19201                                    && selection.start <= nested_end_row
19202                            }) {
19203                                to_fold.push(crease);
19204                            }
19205                        }
19206
19207                        start_row = nested_end_row + 1;
19208                    }
19209                    None => start_row += 1,
19210                }
19211            }
19212        }
19213
19214        self.fold_creases(to_fold, true, window, cx);
19215    }
19216
19217    pub fn fold_at_level_1(
19218        &mut self,
19219        _: &actions::FoldAtLevel1,
19220        window: &mut Window,
19221        cx: &mut Context<Self>,
19222    ) {
19223        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19224    }
19225
19226    pub fn fold_at_level_2(
19227        &mut self,
19228        _: &actions::FoldAtLevel2,
19229        window: &mut Window,
19230        cx: &mut Context<Self>,
19231    ) {
19232        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19233    }
19234
19235    pub fn fold_at_level_3(
19236        &mut self,
19237        _: &actions::FoldAtLevel3,
19238        window: &mut Window,
19239        cx: &mut Context<Self>,
19240    ) {
19241        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19242    }
19243
19244    pub fn fold_at_level_4(
19245        &mut self,
19246        _: &actions::FoldAtLevel4,
19247        window: &mut Window,
19248        cx: &mut Context<Self>,
19249    ) {
19250        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19251    }
19252
19253    pub fn fold_at_level_5(
19254        &mut self,
19255        _: &actions::FoldAtLevel5,
19256        window: &mut Window,
19257        cx: &mut Context<Self>,
19258    ) {
19259        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19260    }
19261
19262    pub fn fold_at_level_6(
19263        &mut self,
19264        _: &actions::FoldAtLevel6,
19265        window: &mut Window,
19266        cx: &mut Context<Self>,
19267    ) {
19268        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19269    }
19270
19271    pub fn fold_at_level_7(
19272        &mut self,
19273        _: &actions::FoldAtLevel7,
19274        window: &mut Window,
19275        cx: &mut Context<Self>,
19276    ) {
19277        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19278    }
19279
19280    pub fn fold_at_level_8(
19281        &mut self,
19282        _: &actions::FoldAtLevel8,
19283        window: &mut Window,
19284        cx: &mut Context<Self>,
19285    ) {
19286        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19287    }
19288
19289    pub fn fold_at_level_9(
19290        &mut self,
19291        _: &actions::FoldAtLevel9,
19292        window: &mut Window,
19293        cx: &mut Context<Self>,
19294    ) {
19295        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19296    }
19297
19298    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19299        if self.buffer.read(cx).is_singleton() {
19300            let mut fold_ranges = Vec::new();
19301            let snapshot = self.buffer.read(cx).snapshot(cx);
19302
19303            for row in 0..snapshot.max_row().0 {
19304                if let Some(foldable_range) = self
19305                    .snapshot(window, cx)
19306                    .crease_for_buffer_row(MultiBufferRow(row))
19307                {
19308                    fold_ranges.push(foldable_range);
19309                }
19310            }
19311
19312            self.fold_creases(fold_ranges, true, window, cx);
19313        } else {
19314            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19315                editor
19316                    .update_in(cx, |editor, _, cx| {
19317                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19318                            editor.fold_buffer(buffer_id, cx);
19319                        }
19320                    })
19321                    .ok();
19322            });
19323        }
19324        cx.emit(SearchEvent::ResultsCollapsedChanged(
19325            CollapseDirection::Collapsed,
19326        ));
19327    }
19328
19329    pub fn fold_function_bodies(
19330        &mut self,
19331        _: &actions::FoldFunctionBodies,
19332        window: &mut Window,
19333        cx: &mut Context<Self>,
19334    ) {
19335        let snapshot = self.buffer.read(cx).snapshot(cx);
19336
19337        let ranges = snapshot
19338            .text_object_ranges(
19339                MultiBufferOffset(0)..snapshot.len(),
19340                TreeSitterOptions::default(),
19341            )
19342            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19343            .collect::<Vec<_>>();
19344
19345        let creases = ranges
19346            .into_iter()
19347            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19348            .collect();
19349
19350        self.fold_creases(creases, true, window, cx);
19351    }
19352
19353    pub fn fold_recursive(
19354        &mut self,
19355        _: &actions::FoldRecursive,
19356        window: &mut Window,
19357        cx: &mut Context<Self>,
19358    ) {
19359        let mut to_fold = Vec::new();
19360        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19361        let selections = self.selections.all_adjusted(&display_map);
19362
19363        for selection in selections {
19364            let range = selection.range().sorted();
19365            let buffer_start_row = range.start.row;
19366
19367            if range.start.row != range.end.row {
19368                let mut found = false;
19369                for row in range.start.row..=range.end.row {
19370                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19371                        found = true;
19372                        to_fold.push(crease);
19373                    }
19374                }
19375                if found {
19376                    continue;
19377                }
19378            }
19379
19380            for row in (0..=range.start.row).rev() {
19381                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19382                    if crease.range().end.row >= buffer_start_row {
19383                        to_fold.push(crease);
19384                    } else {
19385                        break;
19386                    }
19387                }
19388            }
19389        }
19390
19391        self.fold_creases(to_fold, true, window, cx);
19392    }
19393
19394    pub fn fold_at(
19395        &mut self,
19396        buffer_row: MultiBufferRow,
19397        window: &mut Window,
19398        cx: &mut Context<Self>,
19399    ) {
19400        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19401
19402        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19403            let autoscroll = self
19404                .selections
19405                .all::<Point>(&display_map)
19406                .iter()
19407                .any(|selection| crease.range().overlaps(&selection.range()));
19408
19409            self.fold_creases(vec![crease], autoscroll, window, cx);
19410        }
19411    }
19412
19413    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19414        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19415            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19416            let buffer = display_map.buffer_snapshot();
19417            let selections = self.selections.all::<Point>(&display_map);
19418            let ranges = selections
19419                .iter()
19420                .map(|s| {
19421                    let range = s.display_range(&display_map).sorted();
19422                    let mut start = range.start.to_point(&display_map);
19423                    let mut end = range.end.to_point(&display_map);
19424                    start.column = 0;
19425                    end.column = buffer.line_len(MultiBufferRow(end.row));
19426                    start..end
19427                })
19428                .collect::<Vec<_>>();
19429
19430            self.unfold_ranges(&ranges, true, true, cx);
19431        } else {
19432            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19433            let buffer_ids = self
19434                .selections
19435                .disjoint_anchor_ranges()
19436                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19437                .collect::<HashSet<_>>();
19438            for buffer_id in buffer_ids {
19439                self.unfold_buffer(buffer_id, cx);
19440            }
19441        }
19442    }
19443
19444    pub fn unfold_recursive(
19445        &mut self,
19446        _: &UnfoldRecursive,
19447        _window: &mut Window,
19448        cx: &mut Context<Self>,
19449    ) {
19450        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19451        let selections = self.selections.all::<Point>(&display_map);
19452        let ranges = selections
19453            .iter()
19454            .map(|s| {
19455                let mut range = s.display_range(&display_map).sorted();
19456                *range.start.column_mut() = 0;
19457                *range.end.column_mut() = display_map.line_len(range.end.row());
19458                let start = range.start.to_point(&display_map);
19459                let end = range.end.to_point(&display_map);
19460                start..end
19461            })
19462            .collect::<Vec<_>>();
19463
19464        self.unfold_ranges(&ranges, true, true, cx);
19465    }
19466
19467    pub fn unfold_at(
19468        &mut self,
19469        buffer_row: MultiBufferRow,
19470        _window: &mut Window,
19471        cx: &mut Context<Self>,
19472    ) {
19473        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19474
19475        let intersection_range = Point::new(buffer_row.0, 0)
19476            ..Point::new(
19477                buffer_row.0,
19478                display_map.buffer_snapshot().line_len(buffer_row),
19479            );
19480
19481        let autoscroll = self
19482            .selections
19483            .all::<Point>(&display_map)
19484            .iter()
19485            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19486
19487        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19488    }
19489
19490    pub fn unfold_all(
19491        &mut self,
19492        _: &actions::UnfoldAll,
19493        _window: &mut Window,
19494        cx: &mut Context<Self>,
19495    ) {
19496        if self.buffer.read(cx).is_singleton() {
19497            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19498            self.unfold_ranges(
19499                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19500                true,
19501                true,
19502                cx,
19503            );
19504        } else {
19505            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19506                editor
19507                    .update(cx, |editor, cx| {
19508                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19509                            editor.unfold_buffer(buffer_id, cx);
19510                        }
19511                    })
19512                    .ok();
19513            });
19514        }
19515        cx.emit(SearchEvent::ResultsCollapsedChanged(
19516            CollapseDirection::Expanded,
19517        ));
19518    }
19519
19520    pub fn fold_selected_ranges(
19521        &mut self,
19522        _: &FoldSelectedRanges,
19523        window: &mut Window,
19524        cx: &mut Context<Self>,
19525    ) {
19526        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19527        let selections = self.selections.all_adjusted(&display_map);
19528        let ranges = selections
19529            .into_iter()
19530            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19531            .collect::<Vec<_>>();
19532        self.fold_creases(ranges, true, window, cx);
19533    }
19534
19535    pub fn fold_ranges<T: ToOffset + Clone>(
19536        &mut self,
19537        ranges: Vec<Range<T>>,
19538        auto_scroll: bool,
19539        window: &mut Window,
19540        cx: &mut Context<Self>,
19541    ) {
19542        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19543        let ranges = ranges
19544            .into_iter()
19545            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19546            .collect::<Vec<_>>();
19547        self.fold_creases(ranges, auto_scroll, window, cx);
19548    }
19549
19550    pub fn fold_creases<T: ToOffset + Clone>(
19551        &mut self,
19552        creases: Vec<Crease<T>>,
19553        auto_scroll: bool,
19554        _window: &mut Window,
19555        cx: &mut Context<Self>,
19556    ) {
19557        if creases.is_empty() {
19558            return;
19559        }
19560
19561        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19562
19563        if auto_scroll {
19564            self.request_autoscroll(Autoscroll::fit(), cx);
19565        }
19566
19567        cx.notify();
19568
19569        self.scrollbar_marker_state.dirty = true;
19570        self.folds_did_change(cx);
19571    }
19572
19573    /// Removes any folds whose ranges intersect any of the given ranges.
19574    pub fn unfold_ranges<T: ToOffset + Clone>(
19575        &mut self,
19576        ranges: &[Range<T>],
19577        inclusive: bool,
19578        auto_scroll: bool,
19579        cx: &mut Context<Self>,
19580    ) {
19581        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19582            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19583        });
19584        self.folds_did_change(cx);
19585    }
19586
19587    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19588        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19589            return;
19590        }
19591
19592        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19593        self.display_map.update(cx, |display_map, cx| {
19594            display_map.fold_buffers([buffer_id], cx)
19595        });
19596
19597        let snapshot = self.display_snapshot(cx);
19598        self.selections.change_with(&snapshot, |selections| {
19599            selections.remove_selections_from_buffer(buffer_id);
19600        });
19601
19602        cx.emit(EditorEvent::BufferFoldToggled {
19603            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19604            folded: true,
19605        });
19606        cx.notify();
19607    }
19608
19609    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19610        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19611            return;
19612        }
19613        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19614        self.display_map.update(cx, |display_map, cx| {
19615            display_map.unfold_buffers([buffer_id], cx);
19616        });
19617        cx.emit(EditorEvent::BufferFoldToggled {
19618            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19619            folded: false,
19620        });
19621        cx.notify();
19622    }
19623
19624    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19625        self.display_map.read(cx).is_buffer_folded(buffer)
19626    }
19627
19628    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19629        self.display_map.read(cx).folded_buffers()
19630    }
19631
19632    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19633        self.display_map.update(cx, |display_map, cx| {
19634            display_map.disable_header_for_buffer(buffer_id, cx);
19635        });
19636        cx.notify();
19637    }
19638
19639    /// Removes any folds with the given ranges.
19640    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19641        &mut self,
19642        ranges: &[Range<T>],
19643        type_id: TypeId,
19644        auto_scroll: bool,
19645        cx: &mut Context<Self>,
19646    ) {
19647        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19648            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19649        });
19650        self.folds_did_change(cx);
19651    }
19652
19653    fn remove_folds_with<T: ToOffset + Clone>(
19654        &mut self,
19655        ranges: &[Range<T>],
19656        auto_scroll: bool,
19657        cx: &mut Context<Self>,
19658        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19659    ) {
19660        if ranges.is_empty() {
19661            return;
19662        }
19663
19664        let mut buffers_affected = HashSet::default();
19665        let multi_buffer = self.buffer().read(cx);
19666        for range in ranges {
19667            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19668                buffers_affected.insert(buffer.read(cx).remote_id());
19669            };
19670        }
19671
19672        self.display_map.update(cx, update);
19673
19674        if auto_scroll {
19675            self.request_autoscroll(Autoscroll::fit(), cx);
19676        }
19677
19678        cx.notify();
19679        self.scrollbar_marker_state.dirty = true;
19680        self.active_indent_guides_state.dirty = true;
19681    }
19682
19683    pub fn update_renderer_widths(
19684        &mut self,
19685        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19686        cx: &mut Context<Self>,
19687    ) -> bool {
19688        self.display_map
19689            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19690    }
19691
19692    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19693        self.display_map.read(cx).fold_placeholder.clone()
19694    }
19695
19696    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19697        self.use_base_text_line_numbers = show;
19698    }
19699
19700    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19701        self.buffer.update(cx, |buffer, cx| {
19702            buffer.set_all_diff_hunks_expanded(cx);
19703        });
19704    }
19705
19706    pub fn expand_all_diff_hunks(
19707        &mut self,
19708        _: &ExpandAllDiffHunks,
19709        _window: &mut Window,
19710        cx: &mut Context<Self>,
19711    ) {
19712        self.buffer.update(cx, |buffer, cx| {
19713            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19714        });
19715    }
19716
19717    pub fn collapse_all_diff_hunks(
19718        &mut self,
19719        _: &CollapseAllDiffHunks,
19720        _window: &mut Window,
19721        cx: &mut Context<Self>,
19722    ) {
19723        self.buffer.update(cx, |buffer, cx| {
19724            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19725        });
19726    }
19727
19728    pub fn toggle_selected_diff_hunks(
19729        &mut self,
19730        _: &ToggleSelectedDiffHunks,
19731        _window: &mut Window,
19732        cx: &mut Context<Self>,
19733    ) {
19734        let ranges: Vec<_> = self
19735            .selections
19736            .disjoint_anchors()
19737            .iter()
19738            .map(|s| s.range())
19739            .collect();
19740        self.toggle_diff_hunks_in_ranges(ranges, cx);
19741    }
19742
19743    pub fn diff_hunks_in_ranges<'a>(
19744        &'a self,
19745        ranges: &'a [Range<Anchor>],
19746        buffer: &'a MultiBufferSnapshot,
19747    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19748        ranges.iter().flat_map(move |range| {
19749            let end_excerpt_id = range.end.excerpt_id;
19750            let range = range.to_point(buffer);
19751            let mut peek_end = range.end;
19752            if range.end.row < buffer.max_row().0 {
19753                peek_end = Point::new(range.end.row + 1, 0);
19754            }
19755            buffer
19756                .diff_hunks_in_range(range.start..peek_end)
19757                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19758        })
19759    }
19760
19761    pub fn has_stageable_diff_hunks_in_ranges(
19762        &self,
19763        ranges: &[Range<Anchor>],
19764        snapshot: &MultiBufferSnapshot,
19765    ) -> bool {
19766        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19767        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19768    }
19769
19770    pub fn toggle_staged_selected_diff_hunks(
19771        &mut self,
19772        _: &::git::ToggleStaged,
19773        _: &mut Window,
19774        cx: &mut Context<Self>,
19775    ) {
19776        let snapshot = self.buffer.read(cx).snapshot(cx);
19777        let ranges: Vec<_> = self
19778            .selections
19779            .disjoint_anchors()
19780            .iter()
19781            .map(|s| s.range())
19782            .collect();
19783        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19784        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19785    }
19786
19787    pub fn set_render_diff_hunk_controls(
19788        &mut self,
19789        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19790        cx: &mut Context<Self>,
19791    ) {
19792        self.render_diff_hunk_controls = render_diff_hunk_controls;
19793        cx.notify();
19794    }
19795
19796    pub fn stage_and_next(
19797        &mut self,
19798        _: &::git::StageAndNext,
19799        window: &mut Window,
19800        cx: &mut Context<Self>,
19801    ) {
19802        self.do_stage_or_unstage_and_next(true, window, cx);
19803    }
19804
19805    pub fn unstage_and_next(
19806        &mut self,
19807        _: &::git::UnstageAndNext,
19808        window: &mut Window,
19809        cx: &mut Context<Self>,
19810    ) {
19811        self.do_stage_or_unstage_and_next(false, window, cx);
19812    }
19813
19814    pub fn stage_or_unstage_diff_hunks(
19815        &mut self,
19816        stage: bool,
19817        ranges: Vec<Range<Anchor>>,
19818        cx: &mut Context<Self>,
19819    ) {
19820        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19821        cx.spawn(async move |this, cx| {
19822            task.await?;
19823            this.update(cx, |this, cx| {
19824                let snapshot = this.buffer.read(cx).snapshot(cx);
19825                let chunk_by = this
19826                    .diff_hunks_in_ranges(&ranges, &snapshot)
19827                    .chunk_by(|hunk| hunk.buffer_id);
19828                for (buffer_id, hunks) in &chunk_by {
19829                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19830                }
19831            })
19832        })
19833        .detach_and_log_err(cx);
19834    }
19835
19836    fn save_buffers_for_ranges_if_needed(
19837        &mut self,
19838        ranges: &[Range<Anchor>],
19839        cx: &mut Context<Editor>,
19840    ) -> Task<Result<()>> {
19841        let multibuffer = self.buffer.read(cx);
19842        let snapshot = multibuffer.read(cx);
19843        let buffer_ids: HashSet<_> = ranges
19844            .iter()
19845            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19846            .collect();
19847        drop(snapshot);
19848
19849        let mut buffers = HashSet::default();
19850        for buffer_id in buffer_ids {
19851            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19852                let buffer = buffer_entity.read(cx);
19853                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19854                {
19855                    buffers.insert(buffer_entity);
19856                }
19857            }
19858        }
19859
19860        if let Some(project) = &self.project {
19861            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19862        } else {
19863            Task::ready(Ok(()))
19864        }
19865    }
19866
19867    fn do_stage_or_unstage_and_next(
19868        &mut self,
19869        stage: bool,
19870        window: &mut Window,
19871        cx: &mut Context<Self>,
19872    ) {
19873        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19874
19875        if ranges.iter().any(|range| range.start != range.end) {
19876            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19877            return;
19878        }
19879
19880        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19881        let snapshot = self.snapshot(window, cx);
19882        let position = self
19883            .selections
19884            .newest::<Point>(&snapshot.display_snapshot)
19885            .head();
19886        let mut row = snapshot
19887            .buffer_snapshot()
19888            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19889            .find(|hunk| hunk.row_range.start.0 > position.row)
19890            .map(|hunk| hunk.row_range.start);
19891
19892        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19893        // Outside of the project diff editor, wrap around to the beginning.
19894        if !all_diff_hunks_expanded {
19895            row = row.or_else(|| {
19896                snapshot
19897                    .buffer_snapshot()
19898                    .diff_hunks_in_range(Point::zero()..position)
19899                    .find(|hunk| hunk.row_range.end.0 < position.row)
19900                    .map(|hunk| hunk.row_range.start)
19901            });
19902        }
19903
19904        if let Some(row) = row {
19905            let destination = Point::new(row.0, 0);
19906            let autoscroll = Autoscroll::center();
19907
19908            self.unfold_ranges(&[destination..destination], false, false, cx);
19909            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19910                s.select_ranges([destination..destination]);
19911            });
19912        }
19913    }
19914
19915    fn do_stage_or_unstage(
19916        &self,
19917        stage: bool,
19918        buffer_id: BufferId,
19919        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19920        cx: &mut App,
19921    ) -> Option<()> {
19922        let project = self.project()?;
19923        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19924        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19925        let buffer_snapshot = buffer.read(cx).snapshot();
19926        let file_exists = buffer_snapshot
19927            .file()
19928            .is_some_and(|file| file.disk_state().exists());
19929        diff.update(cx, |diff, cx| {
19930            diff.stage_or_unstage_hunks(
19931                stage,
19932                &hunks
19933                    .map(|hunk| buffer_diff::DiffHunk {
19934                        buffer_range: hunk.buffer_range,
19935                        // We don't need to pass in word diffs here because they're only used for rendering and
19936                        // this function changes internal state
19937                        base_word_diffs: Vec::default(),
19938                        buffer_word_diffs: Vec::default(),
19939                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19940                            ..hunk.diff_base_byte_range.end.0,
19941                        secondary_status: hunk.secondary_status,
19942                        range: Point::zero()..Point::zero(), // unused
19943                    })
19944                    .collect::<Vec<_>>(),
19945                &buffer_snapshot,
19946                file_exists,
19947                cx,
19948            )
19949        });
19950        None
19951    }
19952
19953    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19954        let ranges: Vec<_> = self
19955            .selections
19956            .disjoint_anchors()
19957            .iter()
19958            .map(|s| s.range())
19959            .collect();
19960        self.buffer
19961            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19962    }
19963
19964    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19965        self.buffer.update(cx, |buffer, cx| {
19966            let ranges = vec![Anchor::min()..Anchor::max()];
19967            if !buffer.all_diff_hunks_expanded()
19968                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19969            {
19970                buffer.collapse_diff_hunks(ranges, cx);
19971                true
19972            } else {
19973                false
19974            }
19975        })
19976    }
19977
19978    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19979        if self.buffer.read(cx).all_diff_hunks_expanded() {
19980            return true;
19981        }
19982        let ranges = vec![Anchor::min()..Anchor::max()];
19983        self.buffer
19984            .read(cx)
19985            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19986    }
19987
19988    fn toggle_diff_hunks_in_ranges(
19989        &mut self,
19990        ranges: Vec<Range<Anchor>>,
19991        cx: &mut Context<Editor>,
19992    ) {
19993        self.buffer.update(cx, |buffer, cx| {
19994            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19995            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19996        })
19997    }
19998
19999    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20000        self.buffer.update(cx, |buffer, cx| {
20001            let snapshot = buffer.snapshot(cx);
20002            let excerpt_id = range.end.excerpt_id;
20003            let point_range = range.to_point(&snapshot);
20004            let expand = !buffer.single_hunk_is_expanded(range, cx);
20005            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20006        })
20007    }
20008
20009    pub(crate) fn apply_all_diff_hunks(
20010        &mut self,
20011        _: &ApplyAllDiffHunks,
20012        window: &mut Window,
20013        cx: &mut Context<Self>,
20014    ) {
20015        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20016
20017        let buffers = self.buffer.read(cx).all_buffers();
20018        for branch_buffer in buffers {
20019            branch_buffer.update(cx, |branch_buffer, cx| {
20020                branch_buffer.merge_into_base(Vec::new(), cx);
20021            });
20022        }
20023
20024        if let Some(project) = self.project.clone() {
20025            self.save(
20026                SaveOptions {
20027                    format: true,
20028                    autosave: false,
20029                },
20030                project,
20031                window,
20032                cx,
20033            )
20034            .detach_and_log_err(cx);
20035        }
20036    }
20037
20038    pub(crate) fn apply_selected_diff_hunks(
20039        &mut self,
20040        _: &ApplyDiffHunk,
20041        window: &mut Window,
20042        cx: &mut Context<Self>,
20043    ) {
20044        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20045        let snapshot = self.snapshot(window, cx);
20046        let hunks = snapshot.hunks_for_ranges(
20047            self.selections
20048                .all(&snapshot.display_snapshot)
20049                .into_iter()
20050                .map(|selection| selection.range()),
20051        );
20052        let mut ranges_by_buffer = HashMap::default();
20053        self.transact(window, cx, |editor, _window, cx| {
20054            for hunk in hunks {
20055                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20056                    ranges_by_buffer
20057                        .entry(buffer.clone())
20058                        .or_insert_with(Vec::new)
20059                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20060                }
20061            }
20062
20063            for (buffer, ranges) in ranges_by_buffer {
20064                buffer.update(cx, |buffer, cx| {
20065                    buffer.merge_into_base(ranges, cx);
20066                });
20067            }
20068        });
20069
20070        if let Some(project) = self.project.clone() {
20071            self.save(
20072                SaveOptions {
20073                    format: true,
20074                    autosave: false,
20075                },
20076                project,
20077                window,
20078                cx,
20079            )
20080            .detach_and_log_err(cx);
20081        }
20082    }
20083
20084    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20085        if hovered != self.gutter_hovered {
20086            self.gutter_hovered = hovered;
20087            cx.notify();
20088        }
20089    }
20090
20091    pub fn insert_blocks(
20092        &mut self,
20093        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20094        autoscroll: Option<Autoscroll>,
20095        cx: &mut Context<Self>,
20096    ) -> Vec<CustomBlockId> {
20097        let blocks = self
20098            .display_map
20099            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20100        if let Some(autoscroll) = autoscroll {
20101            self.request_autoscroll(autoscroll, cx);
20102        }
20103        cx.notify();
20104        blocks
20105    }
20106
20107    pub fn resize_blocks(
20108        &mut self,
20109        heights: HashMap<CustomBlockId, u32>,
20110        autoscroll: Option<Autoscroll>,
20111        cx: &mut Context<Self>,
20112    ) {
20113        self.display_map
20114            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20115        if let Some(autoscroll) = autoscroll {
20116            self.request_autoscroll(autoscroll, cx);
20117        }
20118        cx.notify();
20119    }
20120
20121    pub fn replace_blocks(
20122        &mut self,
20123        renderers: HashMap<CustomBlockId, RenderBlock>,
20124        autoscroll: Option<Autoscroll>,
20125        cx: &mut Context<Self>,
20126    ) {
20127        self.display_map
20128            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20129        if let Some(autoscroll) = autoscroll {
20130            self.request_autoscroll(autoscroll, cx);
20131        }
20132        cx.notify();
20133    }
20134
20135    pub fn remove_blocks(
20136        &mut self,
20137        block_ids: HashSet<CustomBlockId>,
20138        autoscroll: Option<Autoscroll>,
20139        cx: &mut Context<Self>,
20140    ) {
20141        self.display_map.update(cx, |display_map, cx| {
20142            display_map.remove_blocks(block_ids, cx)
20143        });
20144        if let Some(autoscroll) = autoscroll {
20145            self.request_autoscroll(autoscroll, cx);
20146        }
20147        cx.notify();
20148    }
20149
20150    pub fn row_for_block(
20151        &self,
20152        block_id: CustomBlockId,
20153        cx: &mut Context<Self>,
20154    ) -> Option<DisplayRow> {
20155        self.display_map
20156            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20157    }
20158
20159    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20160        self.focused_block = Some(focused_block);
20161    }
20162
20163    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20164        self.focused_block.take()
20165    }
20166
20167    pub fn insert_creases(
20168        &mut self,
20169        creases: impl IntoIterator<Item = Crease<Anchor>>,
20170        cx: &mut Context<Self>,
20171    ) -> Vec<CreaseId> {
20172        self.display_map
20173            .update(cx, |map, cx| map.insert_creases(creases, cx))
20174    }
20175
20176    pub fn remove_creases(
20177        &mut self,
20178        ids: impl IntoIterator<Item = CreaseId>,
20179        cx: &mut Context<Self>,
20180    ) -> Vec<(CreaseId, Range<Anchor>)> {
20181        self.display_map
20182            .update(cx, |map, cx| map.remove_creases(ids, cx))
20183    }
20184
20185    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20186        self.display_map
20187            .update(cx, |map, cx| map.snapshot(cx))
20188            .longest_row()
20189    }
20190
20191    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20192        self.display_map
20193            .update(cx, |map, cx| map.snapshot(cx))
20194            .max_point()
20195    }
20196
20197    pub fn text(&self, cx: &App) -> String {
20198        self.buffer.read(cx).read(cx).text()
20199    }
20200
20201    pub fn is_empty(&self, cx: &App) -> bool {
20202        self.buffer.read(cx).read(cx).is_empty()
20203    }
20204
20205    pub fn text_option(&self, cx: &App) -> Option<String> {
20206        let text = self.text(cx);
20207        let text = text.trim();
20208
20209        if text.is_empty() {
20210            return None;
20211        }
20212
20213        Some(text.to_string())
20214    }
20215
20216    pub fn set_text(
20217        &mut self,
20218        text: impl Into<Arc<str>>,
20219        window: &mut Window,
20220        cx: &mut Context<Self>,
20221    ) {
20222        self.transact(window, cx, |this, _, cx| {
20223            this.buffer
20224                .read(cx)
20225                .as_singleton()
20226                .expect("you can only call set_text on editors for singleton buffers")
20227                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20228        });
20229    }
20230
20231    pub fn display_text(&self, cx: &mut App) -> String {
20232        self.display_map
20233            .update(cx, |map, cx| map.snapshot(cx))
20234            .text()
20235    }
20236
20237    fn create_minimap(
20238        &self,
20239        minimap_settings: MinimapSettings,
20240        window: &mut Window,
20241        cx: &mut Context<Self>,
20242    ) -> Option<Entity<Self>> {
20243        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20244            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20245    }
20246
20247    fn initialize_new_minimap(
20248        &self,
20249        minimap_settings: MinimapSettings,
20250        window: &mut Window,
20251        cx: &mut Context<Self>,
20252    ) -> Entity<Self> {
20253        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20254
20255        let mut minimap = Editor::new_internal(
20256            EditorMode::Minimap {
20257                parent: cx.weak_entity(),
20258            },
20259            self.buffer.clone(),
20260            None,
20261            Some(self.display_map.clone()),
20262            window,
20263            cx,
20264        );
20265        minimap.scroll_manager.clone_state(&self.scroll_manager);
20266        minimap.set_text_style_refinement(TextStyleRefinement {
20267            font_size: Some(MINIMAP_FONT_SIZE),
20268            font_weight: Some(MINIMAP_FONT_WEIGHT),
20269            ..Default::default()
20270        });
20271        minimap.update_minimap_configuration(minimap_settings, cx);
20272        cx.new(|_| minimap)
20273    }
20274
20275    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20276        let current_line_highlight = minimap_settings
20277            .current_line_highlight
20278            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20279        self.set_current_line_highlight(Some(current_line_highlight));
20280    }
20281
20282    pub fn minimap(&self) -> Option<&Entity<Self>> {
20283        self.minimap
20284            .as_ref()
20285            .filter(|_| self.minimap_visibility.visible())
20286    }
20287
20288    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20289        let mut wrap_guides = smallvec![];
20290
20291        if self.show_wrap_guides == Some(false) {
20292            return wrap_guides;
20293        }
20294
20295        let settings = self.buffer.read(cx).language_settings(cx);
20296        if settings.show_wrap_guides {
20297            match self.soft_wrap_mode(cx) {
20298                SoftWrap::Column(soft_wrap) => {
20299                    wrap_guides.push((soft_wrap as usize, true));
20300                }
20301                SoftWrap::Bounded(soft_wrap) => {
20302                    wrap_guides.push((soft_wrap as usize, true));
20303                }
20304                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20305            }
20306            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20307        }
20308
20309        wrap_guides
20310    }
20311
20312    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20313        let settings = self.buffer.read(cx).language_settings(cx);
20314        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20315        match mode {
20316            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20317                SoftWrap::None
20318            }
20319            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20320            language_settings::SoftWrap::PreferredLineLength => {
20321                SoftWrap::Column(settings.preferred_line_length)
20322            }
20323            language_settings::SoftWrap::Bounded => {
20324                SoftWrap::Bounded(settings.preferred_line_length)
20325            }
20326        }
20327    }
20328
20329    pub fn set_soft_wrap_mode(
20330        &mut self,
20331        mode: language_settings::SoftWrap,
20332
20333        cx: &mut Context<Self>,
20334    ) {
20335        self.soft_wrap_mode_override = Some(mode);
20336        cx.notify();
20337    }
20338
20339    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20340        self.hard_wrap = hard_wrap;
20341        cx.notify();
20342    }
20343
20344    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20345        self.text_style_refinement = Some(style);
20346    }
20347
20348    /// called by the Element so we know what style we were most recently rendered with.
20349    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20350        // We intentionally do not inform the display map about the minimap style
20351        // so that wrapping is not recalculated and stays consistent for the editor
20352        // and its linked minimap.
20353        if !self.mode.is_minimap() {
20354            let font = style.text.font();
20355            let font_size = style.text.font_size.to_pixels(window.rem_size());
20356            let display_map = self
20357                .placeholder_display_map
20358                .as_ref()
20359                .filter(|_| self.is_empty(cx))
20360                .unwrap_or(&self.display_map);
20361
20362            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20363        }
20364        self.style = Some(style);
20365    }
20366
20367    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20368        if self.style.is_none() {
20369            self.style = Some(self.create_style(cx));
20370        }
20371        self.style.as_ref().unwrap()
20372    }
20373
20374    // Called by the element. This method is not designed to be called outside of the editor
20375    // element's layout code because it does not notify when rewrapping is computed synchronously.
20376    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20377        if self.is_empty(cx) {
20378            self.placeholder_display_map
20379                .as_ref()
20380                .map_or(false, |display_map| {
20381                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20382                })
20383        } else {
20384            self.display_map
20385                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20386        }
20387    }
20388
20389    pub fn set_soft_wrap(&mut self) {
20390        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20391    }
20392
20393    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20394        if self.soft_wrap_mode_override.is_some() {
20395            self.soft_wrap_mode_override.take();
20396        } else {
20397            let soft_wrap = match self.soft_wrap_mode(cx) {
20398                SoftWrap::GitDiff => return,
20399                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20400                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20401                    language_settings::SoftWrap::None
20402                }
20403            };
20404            self.soft_wrap_mode_override = Some(soft_wrap);
20405        }
20406        cx.notify();
20407    }
20408
20409    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20410        let Some(workspace) = self.workspace() else {
20411            return;
20412        };
20413        let fs = workspace.read(cx).app_state().fs.clone();
20414        let current_show = TabBarSettings::get_global(cx).show;
20415        update_settings_file(fs, cx, move |setting, _| {
20416            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20417        });
20418    }
20419
20420    pub fn toggle_indent_guides(
20421        &mut self,
20422        _: &ToggleIndentGuides,
20423        _: &mut Window,
20424        cx: &mut Context<Self>,
20425    ) {
20426        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20427            self.buffer
20428                .read(cx)
20429                .language_settings(cx)
20430                .indent_guides
20431                .enabled
20432        });
20433        self.show_indent_guides = Some(!currently_enabled);
20434        cx.notify();
20435    }
20436
20437    fn should_show_indent_guides(&self) -> Option<bool> {
20438        self.show_indent_guides
20439    }
20440
20441    pub fn disable_indent_guides_for_buffer(
20442        &mut self,
20443        buffer_id: BufferId,
20444        cx: &mut Context<Self>,
20445    ) {
20446        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20447        cx.notify();
20448    }
20449
20450    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20451        self.buffers_with_disabled_indent_guides
20452            .contains(&buffer_id)
20453    }
20454
20455    pub fn toggle_line_numbers(
20456        &mut self,
20457        _: &ToggleLineNumbers,
20458        _: &mut Window,
20459        cx: &mut Context<Self>,
20460    ) {
20461        let mut editor_settings = EditorSettings::get_global(cx).clone();
20462        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20463        EditorSettings::override_global(editor_settings, cx);
20464    }
20465
20466    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20467        if let Some(show_line_numbers) = self.show_line_numbers {
20468            return show_line_numbers;
20469        }
20470        EditorSettings::get_global(cx).gutter.line_numbers
20471    }
20472
20473    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
20474        match (
20475            self.use_relative_line_numbers,
20476            EditorSettings::get_global(cx).relative_line_numbers,
20477        ) {
20478            (None, setting) => setting,
20479            (Some(false), _) => RelativeLineNumbers::Disabled,
20480            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20481            (Some(true), _) => RelativeLineNumbers::Enabled,
20482        }
20483    }
20484
20485    pub fn toggle_relative_line_numbers(
20486        &mut self,
20487        _: &ToggleRelativeLineNumbers,
20488        _: &mut Window,
20489        cx: &mut Context<Self>,
20490    ) {
20491        let is_relative = self.relative_line_numbers(cx);
20492        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20493    }
20494
20495    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20496        self.use_relative_line_numbers = is_relative;
20497        cx.notify();
20498    }
20499
20500    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20501        self.show_gutter = show_gutter;
20502        cx.notify();
20503    }
20504
20505    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20506        self.show_scrollbars = ScrollbarAxes {
20507            horizontal: show,
20508            vertical: show,
20509        };
20510        cx.notify();
20511    }
20512
20513    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20514        self.show_scrollbars.vertical = show;
20515        cx.notify();
20516    }
20517
20518    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20519        self.show_scrollbars.horizontal = show;
20520        cx.notify();
20521    }
20522
20523    pub fn set_minimap_visibility(
20524        &mut self,
20525        minimap_visibility: MinimapVisibility,
20526        window: &mut Window,
20527        cx: &mut Context<Self>,
20528    ) {
20529        if self.minimap_visibility != minimap_visibility {
20530            if minimap_visibility.visible() && self.minimap.is_none() {
20531                let minimap_settings = EditorSettings::get_global(cx).minimap;
20532                self.minimap =
20533                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20534            }
20535            self.minimap_visibility = minimap_visibility;
20536            cx.notify();
20537        }
20538    }
20539
20540    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20541        self.set_show_scrollbars(false, cx);
20542        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20543    }
20544
20545    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20546        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20547    }
20548
20549    /// Normally the text in full mode and auto height editors is padded on the
20550    /// left side by roughly half a character width for improved hit testing.
20551    ///
20552    /// Use this method to disable this for cases where this is not wanted (e.g.
20553    /// if you want to align the editor text with some other text above or below)
20554    /// or if you want to add this padding to single-line editors.
20555    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20556        self.offset_content = offset_content;
20557        cx.notify();
20558    }
20559
20560    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20561        self.show_line_numbers = Some(show_line_numbers);
20562        cx.notify();
20563    }
20564
20565    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20566        self.disable_expand_excerpt_buttons = true;
20567        cx.notify();
20568    }
20569
20570    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20571        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20572        cx.notify();
20573    }
20574
20575    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20576        self.show_code_actions = Some(show_code_actions);
20577        cx.notify();
20578    }
20579
20580    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20581        self.show_runnables = Some(show_runnables);
20582        cx.notify();
20583    }
20584
20585    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20586        self.show_breakpoints = Some(show_breakpoints);
20587        cx.notify();
20588    }
20589
20590    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20591        if self.display_map.read(cx).masked != masked {
20592            self.display_map.update(cx, |map, _| map.masked = masked);
20593        }
20594        cx.notify()
20595    }
20596
20597    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20598        self.show_wrap_guides = Some(show_wrap_guides);
20599        cx.notify();
20600    }
20601
20602    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20603        self.show_indent_guides = Some(show_indent_guides);
20604        cx.notify();
20605    }
20606
20607    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20608        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20609            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20610                && let Some(dir) = file.abs_path(cx).parent()
20611            {
20612                return Some(dir.to_owned());
20613            }
20614        }
20615
20616        None
20617    }
20618
20619    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20620        self.active_excerpt(cx)?
20621            .1
20622            .read(cx)
20623            .file()
20624            .and_then(|f| f.as_local())
20625    }
20626
20627    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20628        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20629            let buffer = buffer.read(cx);
20630            if let Some(project_path) = buffer.project_path(cx) {
20631                let project = self.project()?.read(cx);
20632                project.absolute_path(&project_path, cx)
20633            } else {
20634                buffer
20635                    .file()
20636                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20637            }
20638        })
20639    }
20640
20641    pub fn reveal_in_finder(
20642        &mut self,
20643        _: &RevealInFileManager,
20644        _window: &mut Window,
20645        cx: &mut Context<Self>,
20646    ) {
20647        if let Some(target) = self.target_file(cx) {
20648            cx.reveal_path(&target.abs_path(cx));
20649        }
20650    }
20651
20652    pub fn copy_path(
20653        &mut self,
20654        _: &zed_actions::workspace::CopyPath,
20655        _window: &mut Window,
20656        cx: &mut Context<Self>,
20657    ) {
20658        if let Some(path) = self.target_file_abs_path(cx)
20659            && let Some(path) = path.to_str()
20660        {
20661            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20662        } else {
20663            cx.propagate();
20664        }
20665    }
20666
20667    pub fn copy_relative_path(
20668        &mut self,
20669        _: &zed_actions::workspace::CopyRelativePath,
20670        _window: &mut Window,
20671        cx: &mut Context<Self>,
20672    ) {
20673        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20674            let project = self.project()?.read(cx);
20675            let path = buffer.read(cx).file()?.path();
20676            let path = path.display(project.path_style(cx));
20677            Some(path)
20678        }) {
20679            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20680        } else {
20681            cx.propagate();
20682        }
20683    }
20684
20685    /// Returns the project path for the editor's buffer, if any buffer is
20686    /// opened in the editor.
20687    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20688        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20689            buffer.read(cx).project_path(cx)
20690        } else {
20691            None
20692        }
20693    }
20694
20695    // Returns true if the editor handled a go-to-line request
20696    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20697        maybe!({
20698            let breakpoint_store = self.breakpoint_store.as_ref()?;
20699
20700            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20701            else {
20702                self.clear_row_highlights::<ActiveDebugLine>();
20703                return None;
20704            };
20705
20706            let position = active_stack_frame.position;
20707            let buffer_id = position.buffer_id?;
20708            let snapshot = self
20709                .project
20710                .as_ref()?
20711                .read(cx)
20712                .buffer_for_id(buffer_id, cx)?
20713                .read(cx)
20714                .snapshot();
20715
20716            let mut handled = false;
20717            for (id, ExcerptRange { context, .. }) in
20718                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20719            {
20720                if context.start.cmp(&position, &snapshot).is_ge()
20721                    || context.end.cmp(&position, &snapshot).is_lt()
20722                {
20723                    continue;
20724                }
20725                let snapshot = self.buffer.read(cx).snapshot(cx);
20726                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20727
20728                handled = true;
20729                self.clear_row_highlights::<ActiveDebugLine>();
20730
20731                self.go_to_line::<ActiveDebugLine>(
20732                    multibuffer_anchor,
20733                    Some(cx.theme().colors().editor_debugger_active_line_background),
20734                    window,
20735                    cx,
20736                );
20737
20738                cx.notify();
20739            }
20740
20741            handled.then_some(())
20742        })
20743        .is_some()
20744    }
20745
20746    pub fn copy_file_name_without_extension(
20747        &mut self,
20748        _: &CopyFileNameWithoutExtension,
20749        _: &mut Window,
20750        cx: &mut Context<Self>,
20751    ) {
20752        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20753            let file = buffer.read(cx).file()?;
20754            file.path().file_stem()
20755        }) {
20756            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20757        }
20758    }
20759
20760    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20761        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20762            let file = buffer.read(cx).file()?;
20763            Some(file.file_name(cx))
20764        }) {
20765            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20766        }
20767    }
20768
20769    pub fn toggle_git_blame(
20770        &mut self,
20771        _: &::git::Blame,
20772        window: &mut Window,
20773        cx: &mut Context<Self>,
20774    ) {
20775        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20776
20777        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20778            self.start_git_blame(true, window, cx);
20779        }
20780
20781        cx.notify();
20782    }
20783
20784    pub fn toggle_git_blame_inline(
20785        &mut self,
20786        _: &ToggleGitBlameInline,
20787        window: &mut Window,
20788        cx: &mut Context<Self>,
20789    ) {
20790        self.toggle_git_blame_inline_internal(true, window, cx);
20791        cx.notify();
20792    }
20793
20794    pub fn open_git_blame_commit(
20795        &mut self,
20796        _: &OpenGitBlameCommit,
20797        window: &mut Window,
20798        cx: &mut Context<Self>,
20799    ) {
20800        self.open_git_blame_commit_internal(window, cx);
20801    }
20802
20803    fn open_git_blame_commit_internal(
20804        &mut self,
20805        window: &mut Window,
20806        cx: &mut Context<Self>,
20807    ) -> Option<()> {
20808        let blame = self.blame.as_ref()?;
20809        let snapshot = self.snapshot(window, cx);
20810        let cursor = self
20811            .selections
20812            .newest::<Point>(&snapshot.display_snapshot)
20813            .head();
20814        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20815        let (_, blame_entry) = blame
20816            .update(cx, |blame, cx| {
20817                blame
20818                    .blame_for_rows(
20819                        &[RowInfo {
20820                            buffer_id: Some(buffer.remote_id()),
20821                            buffer_row: Some(point.row),
20822                            ..Default::default()
20823                        }],
20824                        cx,
20825                    )
20826                    .next()
20827            })
20828            .flatten()?;
20829        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20830        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20831        let workspace = self.workspace()?.downgrade();
20832        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20833        None
20834    }
20835
20836    pub fn git_blame_inline_enabled(&self) -> bool {
20837        self.git_blame_inline_enabled
20838    }
20839
20840    pub fn toggle_selection_menu(
20841        &mut self,
20842        _: &ToggleSelectionMenu,
20843        _: &mut Window,
20844        cx: &mut Context<Self>,
20845    ) {
20846        self.show_selection_menu = self
20847            .show_selection_menu
20848            .map(|show_selections_menu| !show_selections_menu)
20849            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20850
20851        cx.notify();
20852    }
20853
20854    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20855        self.show_selection_menu
20856            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20857    }
20858
20859    fn start_git_blame(
20860        &mut self,
20861        user_triggered: bool,
20862        window: &mut Window,
20863        cx: &mut Context<Self>,
20864    ) {
20865        if let Some(project) = self.project() {
20866            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20867                && buffer.read(cx).file().is_none()
20868            {
20869                return;
20870            }
20871
20872            let focused = self.focus_handle(cx).contains_focused(window, cx);
20873
20874            let project = project.clone();
20875            let blame = cx
20876                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20877            self.blame_subscription =
20878                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20879            self.blame = Some(blame);
20880        }
20881    }
20882
20883    fn toggle_git_blame_inline_internal(
20884        &mut self,
20885        user_triggered: bool,
20886        window: &mut Window,
20887        cx: &mut Context<Self>,
20888    ) {
20889        if self.git_blame_inline_enabled {
20890            self.git_blame_inline_enabled = false;
20891            self.show_git_blame_inline = false;
20892            self.show_git_blame_inline_delay_task.take();
20893        } else {
20894            self.git_blame_inline_enabled = true;
20895            self.start_git_blame_inline(user_triggered, window, cx);
20896        }
20897
20898        cx.notify();
20899    }
20900
20901    fn start_git_blame_inline(
20902        &mut self,
20903        user_triggered: bool,
20904        window: &mut Window,
20905        cx: &mut Context<Self>,
20906    ) {
20907        self.start_git_blame(user_triggered, window, cx);
20908
20909        if ProjectSettings::get_global(cx)
20910            .git
20911            .inline_blame_delay()
20912            .is_some()
20913        {
20914            self.start_inline_blame_timer(window, cx);
20915        } else {
20916            self.show_git_blame_inline = true
20917        }
20918    }
20919
20920    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20921        self.blame.as_ref()
20922    }
20923
20924    pub fn show_git_blame_gutter(&self) -> bool {
20925        self.show_git_blame_gutter
20926    }
20927
20928    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20929        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20930    }
20931
20932    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20933        self.show_git_blame_inline
20934            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20935            && !self.newest_selection_head_on_empty_line(cx)
20936            && self.has_blame_entries(cx)
20937    }
20938
20939    fn has_blame_entries(&self, cx: &App) -> bool {
20940        self.blame()
20941            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20942    }
20943
20944    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20945        let cursor_anchor = self.selections.newest_anchor().head();
20946
20947        let snapshot = self.buffer.read(cx).snapshot(cx);
20948        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20949
20950        snapshot.line_len(buffer_row) == 0
20951    }
20952
20953    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20954        let buffer_and_selection = maybe!({
20955            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20956            let selection_range = selection.range();
20957
20958            let multi_buffer = self.buffer().read(cx);
20959            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20960            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20961
20962            let (buffer, range, _) = if selection.reversed {
20963                buffer_ranges.first()
20964            } else {
20965                buffer_ranges.last()
20966            }?;
20967
20968            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
20969            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
20970
20971            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
20972                let selection = start_row_in_buffer..end_row_in_buffer;
20973
20974                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
20975            };
20976
20977            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
20978
20979            Some((
20980                multi_buffer.buffer(buffer.remote_id()).unwrap(),
20981                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, buffer)
20982                    ..buffer_diff_snapshot.row_to_base_text_row(end_row_in_buffer, buffer),
20983            ))
20984        });
20985
20986        let Some((buffer, selection)) = buffer_and_selection else {
20987            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20988        };
20989
20990        let Some(project) = self.project() else {
20991            return Task::ready(Err(anyhow!("editor does not have project")));
20992        };
20993
20994        project.update(cx, |project, cx| {
20995            project.get_permalink_to_line(&buffer, selection, cx)
20996        })
20997    }
20998
20999    pub fn copy_permalink_to_line(
21000        &mut self,
21001        _: &CopyPermalinkToLine,
21002        window: &mut Window,
21003        cx: &mut Context<Self>,
21004    ) {
21005        let permalink_task = self.get_permalink_to_line(cx);
21006        let workspace = self.workspace();
21007
21008        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21009            Ok(permalink) => {
21010                cx.update(|_, cx| {
21011                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21012                })
21013                .ok();
21014            }
21015            Err(err) => {
21016                let message = format!("Failed to copy permalink: {err}");
21017
21018                anyhow::Result::<()>::Err(err).log_err();
21019
21020                if let Some(workspace) = workspace {
21021                    workspace
21022                        .update_in(cx, |workspace, _, cx| {
21023                            struct CopyPermalinkToLine;
21024
21025                            workspace.show_toast(
21026                                Toast::new(
21027                                    NotificationId::unique::<CopyPermalinkToLine>(),
21028                                    message,
21029                                ),
21030                                cx,
21031                            )
21032                        })
21033                        .ok();
21034                }
21035            }
21036        })
21037        .detach();
21038    }
21039
21040    pub fn copy_file_location(
21041        &mut self,
21042        _: &CopyFileLocation,
21043        _: &mut Window,
21044        cx: &mut Context<Self>,
21045    ) {
21046        let selection = self
21047            .selections
21048            .newest::<Point>(&self.display_snapshot(cx))
21049            .start
21050            .row
21051            + 1;
21052        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21053            let project = self.project()?.read(cx);
21054            let file = buffer.read(cx).file()?;
21055            let path = file.path().display(project.path_style(cx));
21056
21057            Some(format!("{path}:{selection}"))
21058        }) {
21059            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21060        }
21061    }
21062
21063    pub fn open_permalink_to_line(
21064        &mut self,
21065        _: &OpenPermalinkToLine,
21066        window: &mut Window,
21067        cx: &mut Context<Self>,
21068    ) {
21069        let permalink_task = self.get_permalink_to_line(cx);
21070        let workspace = self.workspace();
21071
21072        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21073            Ok(permalink) => {
21074                cx.update(|_, cx| {
21075                    cx.open_url(permalink.as_ref());
21076                })
21077                .ok();
21078            }
21079            Err(err) => {
21080                let message = format!("Failed to open permalink: {err}");
21081
21082                anyhow::Result::<()>::Err(err).log_err();
21083
21084                if let Some(workspace) = workspace {
21085                    workspace
21086                        .update(cx, |workspace, cx| {
21087                            struct OpenPermalinkToLine;
21088
21089                            workspace.show_toast(
21090                                Toast::new(
21091                                    NotificationId::unique::<OpenPermalinkToLine>(),
21092                                    message,
21093                                ),
21094                                cx,
21095                            )
21096                        })
21097                        .ok();
21098                }
21099            }
21100        })
21101        .detach();
21102    }
21103
21104    pub fn insert_uuid_v4(
21105        &mut self,
21106        _: &InsertUuidV4,
21107        window: &mut Window,
21108        cx: &mut Context<Self>,
21109    ) {
21110        self.insert_uuid(UuidVersion::V4, window, cx);
21111    }
21112
21113    pub fn insert_uuid_v7(
21114        &mut self,
21115        _: &InsertUuidV7,
21116        window: &mut Window,
21117        cx: &mut Context<Self>,
21118    ) {
21119        self.insert_uuid(UuidVersion::V7, window, cx);
21120    }
21121
21122    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21123        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21124        self.transact(window, cx, |this, window, cx| {
21125            let edits = this
21126                .selections
21127                .all::<Point>(&this.display_snapshot(cx))
21128                .into_iter()
21129                .map(|selection| {
21130                    let uuid = match version {
21131                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21132                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21133                    };
21134
21135                    (selection.range(), uuid.to_string())
21136                });
21137            this.edit(edits, cx);
21138            this.refresh_edit_prediction(true, false, window, cx);
21139        });
21140    }
21141
21142    pub fn open_selections_in_multibuffer(
21143        &mut self,
21144        _: &OpenSelectionsInMultibuffer,
21145        window: &mut Window,
21146        cx: &mut Context<Self>,
21147    ) {
21148        let multibuffer = self.buffer.read(cx);
21149
21150        let Some(buffer) = multibuffer.as_singleton() else {
21151            return;
21152        };
21153
21154        let Some(workspace) = self.workspace() else {
21155            return;
21156        };
21157
21158        let title = multibuffer.title(cx).to_string();
21159
21160        let locations = self
21161            .selections
21162            .all_anchors(&self.display_snapshot(cx))
21163            .iter()
21164            .map(|selection| {
21165                (
21166                    buffer.clone(),
21167                    (selection.start.text_anchor..selection.end.text_anchor)
21168                        .to_point(buffer.read(cx)),
21169                )
21170            })
21171            .into_group_map();
21172
21173        cx.spawn_in(window, async move |_, cx| {
21174            workspace.update_in(cx, |workspace, window, cx| {
21175                Self::open_locations_in_multibuffer(
21176                    workspace,
21177                    locations,
21178                    format!("Selections for '{title}'"),
21179                    false,
21180                    false,
21181                    MultibufferSelectionMode::All,
21182                    window,
21183                    cx,
21184                );
21185            })
21186        })
21187        .detach();
21188    }
21189
21190    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21191    /// last highlight added will be used.
21192    ///
21193    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21194    pub fn highlight_rows<T: 'static>(
21195        &mut self,
21196        range: Range<Anchor>,
21197        color: Hsla,
21198        options: RowHighlightOptions,
21199        cx: &mut Context<Self>,
21200    ) {
21201        let snapshot = self.buffer().read(cx).snapshot(cx);
21202        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21203        let ix = row_highlights.binary_search_by(|highlight| {
21204            Ordering::Equal
21205                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21206                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21207        });
21208
21209        if let Err(mut ix) = ix {
21210            let index = post_inc(&mut self.highlight_order);
21211
21212            // If this range intersects with the preceding highlight, then merge it with
21213            // the preceding highlight. Otherwise insert a new highlight.
21214            let mut merged = false;
21215            if ix > 0 {
21216                let prev_highlight = &mut row_highlights[ix - 1];
21217                if prev_highlight
21218                    .range
21219                    .end
21220                    .cmp(&range.start, &snapshot)
21221                    .is_ge()
21222                {
21223                    ix -= 1;
21224                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21225                        prev_highlight.range.end = range.end;
21226                    }
21227                    merged = true;
21228                    prev_highlight.index = index;
21229                    prev_highlight.color = color;
21230                    prev_highlight.options = options;
21231                }
21232            }
21233
21234            if !merged {
21235                row_highlights.insert(
21236                    ix,
21237                    RowHighlight {
21238                        range,
21239                        index,
21240                        color,
21241                        options,
21242                        type_id: TypeId::of::<T>(),
21243                    },
21244                );
21245            }
21246
21247            // If any of the following highlights intersect with this one, merge them.
21248            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21249                let highlight = &row_highlights[ix];
21250                if next_highlight
21251                    .range
21252                    .start
21253                    .cmp(&highlight.range.end, &snapshot)
21254                    .is_le()
21255                {
21256                    if next_highlight
21257                        .range
21258                        .end
21259                        .cmp(&highlight.range.end, &snapshot)
21260                        .is_gt()
21261                    {
21262                        row_highlights[ix].range.end = next_highlight.range.end;
21263                    }
21264                    row_highlights.remove(ix + 1);
21265                } else {
21266                    break;
21267                }
21268            }
21269        }
21270    }
21271
21272    /// Remove any highlighted row ranges of the given type that intersect the
21273    /// given ranges.
21274    pub fn remove_highlighted_rows<T: 'static>(
21275        &mut self,
21276        ranges_to_remove: Vec<Range<Anchor>>,
21277        cx: &mut Context<Self>,
21278    ) {
21279        let snapshot = self.buffer().read(cx).snapshot(cx);
21280        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21281        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21282        row_highlights.retain(|highlight| {
21283            while let Some(range_to_remove) = ranges_to_remove.peek() {
21284                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21285                    Ordering::Less | Ordering::Equal => {
21286                        ranges_to_remove.next();
21287                    }
21288                    Ordering::Greater => {
21289                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21290                            Ordering::Less | Ordering::Equal => {
21291                                return false;
21292                            }
21293                            Ordering::Greater => break,
21294                        }
21295                    }
21296                }
21297            }
21298
21299            true
21300        })
21301    }
21302
21303    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21304    pub fn clear_row_highlights<T: 'static>(&mut self) {
21305        self.highlighted_rows.remove(&TypeId::of::<T>());
21306    }
21307
21308    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21309    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21310        self.highlighted_rows
21311            .get(&TypeId::of::<T>())
21312            .map_or(&[] as &[_], |vec| vec.as_slice())
21313            .iter()
21314            .map(|highlight| (highlight.range.clone(), highlight.color))
21315    }
21316
21317    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21318    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21319    /// Allows to ignore certain kinds of highlights.
21320    pub fn highlighted_display_rows(
21321        &self,
21322        window: &mut Window,
21323        cx: &mut App,
21324    ) -> BTreeMap<DisplayRow, LineHighlight> {
21325        let snapshot = self.snapshot(window, cx);
21326        let mut used_highlight_orders = HashMap::default();
21327        self.highlighted_rows
21328            .iter()
21329            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21330            .fold(
21331                BTreeMap::<DisplayRow, LineHighlight>::new(),
21332                |mut unique_rows, highlight| {
21333                    let start = highlight.range.start.to_display_point(&snapshot);
21334                    let end = highlight.range.end.to_display_point(&snapshot);
21335                    let start_row = start.row().0;
21336                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21337                    {
21338                        end.row().0.saturating_sub(1)
21339                    } else {
21340                        end.row().0
21341                    };
21342                    for row in start_row..=end_row {
21343                        let used_index =
21344                            used_highlight_orders.entry(row).or_insert(highlight.index);
21345                        if highlight.index >= *used_index {
21346                            *used_index = highlight.index;
21347                            unique_rows.insert(
21348                                DisplayRow(row),
21349                                LineHighlight {
21350                                    include_gutter: highlight.options.include_gutter,
21351                                    border: None,
21352                                    background: highlight.color.into(),
21353                                    type_id: Some(highlight.type_id),
21354                                },
21355                            );
21356                        }
21357                    }
21358                    unique_rows
21359                },
21360            )
21361    }
21362
21363    pub fn highlighted_display_row_for_autoscroll(
21364        &self,
21365        snapshot: &DisplaySnapshot,
21366    ) -> Option<DisplayRow> {
21367        self.highlighted_rows
21368            .values()
21369            .flat_map(|highlighted_rows| highlighted_rows.iter())
21370            .filter_map(|highlight| {
21371                if highlight.options.autoscroll {
21372                    Some(highlight.range.start.to_display_point(snapshot).row())
21373                } else {
21374                    None
21375                }
21376            })
21377            .min()
21378    }
21379
21380    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21381        self.highlight_background::<SearchWithinRange>(
21382            ranges,
21383            |_, colors| colors.colors().editor_document_highlight_read_background,
21384            cx,
21385        )
21386    }
21387
21388    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21389        self.breadcrumb_header = Some(new_header);
21390    }
21391
21392    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21393        self.clear_background_highlights::<SearchWithinRange>(cx);
21394    }
21395
21396    pub fn highlight_background<T: 'static>(
21397        &mut self,
21398        ranges: &[Range<Anchor>],
21399        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21400        cx: &mut Context<Self>,
21401    ) {
21402        self.background_highlights.insert(
21403            HighlightKey::Type(TypeId::of::<T>()),
21404            (Arc::new(color_fetcher), Arc::from(ranges)),
21405        );
21406        self.scrollbar_marker_state.dirty = true;
21407        cx.notify();
21408    }
21409
21410    pub fn highlight_background_key<T: 'static>(
21411        &mut self,
21412        key: usize,
21413        ranges: &[Range<Anchor>],
21414        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21415        cx: &mut Context<Self>,
21416    ) {
21417        self.background_highlights.insert(
21418            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21419            (Arc::new(color_fetcher), Arc::from(ranges)),
21420        );
21421        self.scrollbar_marker_state.dirty = true;
21422        cx.notify();
21423    }
21424
21425    pub fn clear_background_highlights<T: 'static>(
21426        &mut self,
21427        cx: &mut Context<Self>,
21428    ) -> Option<BackgroundHighlight> {
21429        let text_highlights = self
21430            .background_highlights
21431            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21432        if !text_highlights.1.is_empty() {
21433            self.scrollbar_marker_state.dirty = true;
21434            cx.notify();
21435        }
21436        Some(text_highlights)
21437    }
21438
21439    pub fn highlight_gutter<T: 'static>(
21440        &mut self,
21441        ranges: impl Into<Vec<Range<Anchor>>>,
21442        color_fetcher: fn(&App) -> Hsla,
21443        cx: &mut Context<Self>,
21444    ) {
21445        self.gutter_highlights
21446            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21447        cx.notify();
21448    }
21449
21450    pub fn clear_gutter_highlights<T: 'static>(
21451        &mut self,
21452        cx: &mut Context<Self>,
21453    ) -> Option<GutterHighlight> {
21454        cx.notify();
21455        self.gutter_highlights.remove(&TypeId::of::<T>())
21456    }
21457
21458    pub fn insert_gutter_highlight<T: 'static>(
21459        &mut self,
21460        range: Range<Anchor>,
21461        color_fetcher: fn(&App) -> Hsla,
21462        cx: &mut Context<Self>,
21463    ) {
21464        let snapshot = self.buffer().read(cx).snapshot(cx);
21465        let mut highlights = self
21466            .gutter_highlights
21467            .remove(&TypeId::of::<T>())
21468            .map(|(_, highlights)| highlights)
21469            .unwrap_or_default();
21470        let ix = highlights.binary_search_by(|highlight| {
21471            Ordering::Equal
21472                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21473                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21474        });
21475        if let Err(ix) = ix {
21476            highlights.insert(ix, range);
21477        }
21478        self.gutter_highlights
21479            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21480    }
21481
21482    pub fn remove_gutter_highlights<T: 'static>(
21483        &mut self,
21484        ranges_to_remove: Vec<Range<Anchor>>,
21485        cx: &mut Context<Self>,
21486    ) {
21487        let snapshot = self.buffer().read(cx).snapshot(cx);
21488        let Some((color_fetcher, mut gutter_highlights)) =
21489            self.gutter_highlights.remove(&TypeId::of::<T>())
21490        else {
21491            return;
21492        };
21493        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21494        gutter_highlights.retain(|highlight| {
21495            while let Some(range_to_remove) = ranges_to_remove.peek() {
21496                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21497                    Ordering::Less | Ordering::Equal => {
21498                        ranges_to_remove.next();
21499                    }
21500                    Ordering::Greater => {
21501                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21502                            Ordering::Less | Ordering::Equal => {
21503                                return false;
21504                            }
21505                            Ordering::Greater => break,
21506                        }
21507                    }
21508                }
21509            }
21510
21511            true
21512        });
21513        self.gutter_highlights
21514            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21515    }
21516
21517    #[cfg(feature = "test-support")]
21518    pub fn all_text_highlights(
21519        &self,
21520        window: &mut Window,
21521        cx: &mut Context<Self>,
21522    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21523        let snapshot = self.snapshot(window, cx);
21524        self.display_map.update(cx, |display_map, _| {
21525            display_map
21526                .all_text_highlights()
21527                .map(|highlight| {
21528                    let (style, ranges) = highlight.as_ref();
21529                    (
21530                        *style,
21531                        ranges
21532                            .iter()
21533                            .map(|range| range.clone().to_display_points(&snapshot))
21534                            .collect(),
21535                    )
21536                })
21537                .collect()
21538        })
21539    }
21540
21541    #[cfg(feature = "test-support")]
21542    pub fn all_text_background_highlights(
21543        &self,
21544        window: &mut Window,
21545        cx: &mut Context<Self>,
21546    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21547        let snapshot = self.snapshot(window, cx);
21548        let buffer = &snapshot.buffer_snapshot();
21549        let start = buffer.anchor_before(MultiBufferOffset(0));
21550        let end = buffer.anchor_after(buffer.len());
21551        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21552    }
21553
21554    #[cfg(any(test, feature = "test-support"))]
21555    pub fn sorted_background_highlights_in_range(
21556        &self,
21557        search_range: Range<Anchor>,
21558        display_snapshot: &DisplaySnapshot,
21559        theme: &Theme,
21560    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21561        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21562        res.sort_by(|a, b| {
21563            a.0.start
21564                .cmp(&b.0.start)
21565                .then_with(|| a.0.end.cmp(&b.0.end))
21566                .then_with(|| a.1.cmp(&b.1))
21567        });
21568        res
21569    }
21570
21571    #[cfg(feature = "test-support")]
21572    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21573        let snapshot = self.buffer().read(cx).snapshot(cx);
21574
21575        let highlights = self
21576            .background_highlights
21577            .get(&HighlightKey::Type(TypeId::of::<
21578                items::BufferSearchHighlights,
21579            >()));
21580
21581        if let Some((_color, ranges)) = highlights {
21582            ranges
21583                .iter()
21584                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21585                .collect_vec()
21586        } else {
21587            vec![]
21588        }
21589    }
21590
21591    fn document_highlights_for_position<'a>(
21592        &'a self,
21593        position: Anchor,
21594        buffer: &'a MultiBufferSnapshot,
21595    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21596        let read_highlights = self
21597            .background_highlights
21598            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21599            .map(|h| &h.1);
21600        let write_highlights = self
21601            .background_highlights
21602            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21603            .map(|h| &h.1);
21604        let left_position = position.bias_left(buffer);
21605        let right_position = position.bias_right(buffer);
21606        read_highlights
21607            .into_iter()
21608            .chain(write_highlights)
21609            .flat_map(move |ranges| {
21610                let start_ix = match ranges.binary_search_by(|probe| {
21611                    let cmp = probe.end.cmp(&left_position, buffer);
21612                    if cmp.is_ge() {
21613                        Ordering::Greater
21614                    } else {
21615                        Ordering::Less
21616                    }
21617                }) {
21618                    Ok(i) | Err(i) => i,
21619                };
21620
21621                ranges[start_ix..]
21622                    .iter()
21623                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21624            })
21625    }
21626
21627    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21628        self.background_highlights
21629            .get(&HighlightKey::Type(TypeId::of::<T>()))
21630            .is_some_and(|(_, highlights)| !highlights.is_empty())
21631    }
21632
21633    /// Returns all background highlights for a given range.
21634    ///
21635    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21636    pub fn background_highlights_in_range(
21637        &self,
21638        search_range: Range<Anchor>,
21639        display_snapshot: &DisplaySnapshot,
21640        theme: &Theme,
21641    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21642        let mut results = Vec::new();
21643        for (color_fetcher, ranges) in self.background_highlights.values() {
21644            let start_ix = match ranges.binary_search_by(|probe| {
21645                let cmp = probe
21646                    .end
21647                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21648                if cmp.is_gt() {
21649                    Ordering::Greater
21650                } else {
21651                    Ordering::Less
21652                }
21653            }) {
21654                Ok(i) | Err(i) => i,
21655            };
21656            for (index, range) in ranges[start_ix..].iter().enumerate() {
21657                if range
21658                    .start
21659                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21660                    .is_ge()
21661                {
21662                    break;
21663                }
21664
21665                let color = color_fetcher(&(start_ix + index), theme);
21666                let start = range.start.to_display_point(display_snapshot);
21667                let end = range.end.to_display_point(display_snapshot);
21668                results.push((start..end, color))
21669            }
21670        }
21671        results
21672    }
21673
21674    pub fn gutter_highlights_in_range(
21675        &self,
21676        search_range: Range<Anchor>,
21677        display_snapshot: &DisplaySnapshot,
21678        cx: &App,
21679    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21680        let mut results = Vec::new();
21681        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21682            let color = color_fetcher(cx);
21683            let start_ix = match ranges.binary_search_by(|probe| {
21684                let cmp = probe
21685                    .end
21686                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21687                if cmp.is_gt() {
21688                    Ordering::Greater
21689                } else {
21690                    Ordering::Less
21691                }
21692            }) {
21693                Ok(i) | Err(i) => i,
21694            };
21695            for range in &ranges[start_ix..] {
21696                if range
21697                    .start
21698                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21699                    .is_ge()
21700                {
21701                    break;
21702                }
21703
21704                let start = range.start.to_display_point(display_snapshot);
21705                let end = range.end.to_display_point(display_snapshot);
21706                results.push((start..end, color))
21707            }
21708        }
21709        results
21710    }
21711
21712    /// Get the text ranges corresponding to the redaction query
21713    pub fn redacted_ranges(
21714        &self,
21715        search_range: Range<Anchor>,
21716        display_snapshot: &DisplaySnapshot,
21717        cx: &App,
21718    ) -> Vec<Range<DisplayPoint>> {
21719        display_snapshot
21720            .buffer_snapshot()
21721            .redacted_ranges(search_range, |file| {
21722                if let Some(file) = file {
21723                    file.is_private()
21724                        && EditorSettings::get(
21725                            Some(SettingsLocation {
21726                                worktree_id: file.worktree_id(cx),
21727                                path: file.path().as_ref(),
21728                            }),
21729                            cx,
21730                        )
21731                        .redact_private_values
21732                } else {
21733                    false
21734                }
21735            })
21736            .map(|range| {
21737                range.start.to_display_point(display_snapshot)
21738                    ..range.end.to_display_point(display_snapshot)
21739            })
21740            .collect()
21741    }
21742
21743    pub fn highlight_text_key<T: 'static>(
21744        &mut self,
21745        key: usize,
21746        ranges: Vec<Range<Anchor>>,
21747        style: HighlightStyle,
21748        merge: bool,
21749        cx: &mut Context<Self>,
21750    ) {
21751        self.display_map.update(cx, |map, cx| {
21752            map.highlight_text(
21753                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21754                ranges,
21755                style,
21756                merge,
21757                cx,
21758            );
21759        });
21760        cx.notify();
21761    }
21762
21763    pub fn highlight_text<T: 'static>(
21764        &mut self,
21765        ranges: Vec<Range<Anchor>>,
21766        style: HighlightStyle,
21767        cx: &mut Context<Self>,
21768    ) {
21769        self.display_map.update(cx, |map, cx| {
21770            map.highlight_text(
21771                HighlightKey::Type(TypeId::of::<T>()),
21772                ranges,
21773                style,
21774                false,
21775                cx,
21776            )
21777        });
21778        cx.notify();
21779    }
21780
21781    pub fn text_highlights<'a, T: 'static>(
21782        &'a self,
21783        cx: &'a App,
21784    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21785        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21786    }
21787
21788    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21789        let cleared = self
21790            .display_map
21791            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21792        if cleared {
21793            cx.notify();
21794        }
21795    }
21796
21797    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21798        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21799            && self.focus_handle.is_focused(window)
21800    }
21801
21802    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21803        self.show_cursor_when_unfocused = is_enabled;
21804        cx.notify();
21805    }
21806
21807    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21808        cx.notify();
21809    }
21810
21811    fn on_debug_session_event(
21812        &mut self,
21813        _session: Entity<Session>,
21814        event: &SessionEvent,
21815        cx: &mut Context<Self>,
21816    ) {
21817        if let SessionEvent::InvalidateInlineValue = event {
21818            self.refresh_inline_values(cx);
21819        }
21820    }
21821
21822    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21823        let Some(project) = self.project.clone() else {
21824            return;
21825        };
21826
21827        if !self.inline_value_cache.enabled {
21828            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21829            self.splice_inlays(&inlays, Vec::new(), cx);
21830            return;
21831        }
21832
21833        let current_execution_position = self
21834            .highlighted_rows
21835            .get(&TypeId::of::<ActiveDebugLine>())
21836            .and_then(|lines| lines.last().map(|line| line.range.end));
21837
21838        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21839            let inline_values = editor
21840                .update(cx, |editor, cx| {
21841                    let Some(current_execution_position) = current_execution_position else {
21842                        return Some(Task::ready(Ok(Vec::new())));
21843                    };
21844
21845                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21846                        let snapshot = buffer.snapshot(cx);
21847
21848                        let excerpt = snapshot.excerpt_containing(
21849                            current_execution_position..current_execution_position,
21850                        )?;
21851
21852                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21853                    })?;
21854
21855                    let range =
21856                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21857
21858                    project.inline_values(buffer, range, cx)
21859                })
21860                .ok()
21861                .flatten()?
21862                .await
21863                .context("refreshing debugger inlays")
21864                .log_err()?;
21865
21866            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21867
21868            for (buffer_id, inline_value) in inline_values
21869                .into_iter()
21870                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21871            {
21872                buffer_inline_values
21873                    .entry(buffer_id)
21874                    .or_default()
21875                    .push(inline_value);
21876            }
21877
21878            editor
21879                .update(cx, |editor, cx| {
21880                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21881                    let mut new_inlays = Vec::default();
21882
21883                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21884                        let buffer_id = buffer_snapshot.remote_id();
21885                        buffer_inline_values
21886                            .get(&buffer_id)
21887                            .into_iter()
21888                            .flatten()
21889                            .for_each(|hint| {
21890                                let inlay = Inlay::debugger(
21891                                    post_inc(&mut editor.next_inlay_id),
21892                                    Anchor::in_buffer(excerpt_id, hint.position),
21893                                    hint.text(),
21894                                );
21895                                if !inlay.text().chars().contains(&'\n') {
21896                                    new_inlays.push(inlay);
21897                                }
21898                            });
21899                    }
21900
21901                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21902                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21903
21904                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21905                })
21906                .ok()?;
21907            Some(())
21908        });
21909    }
21910
21911    fn on_buffer_event(
21912        &mut self,
21913        multibuffer: &Entity<MultiBuffer>,
21914        event: &multi_buffer::Event,
21915        window: &mut Window,
21916        cx: &mut Context<Self>,
21917    ) {
21918        match event {
21919            multi_buffer::Event::Edited { edited_buffer } => {
21920                self.scrollbar_marker_state.dirty = true;
21921                self.active_indent_guides_state.dirty = true;
21922                self.refresh_active_diagnostics(cx);
21923                self.refresh_code_actions(window, cx);
21924                self.refresh_single_line_folds(window, cx);
21925                self.refresh_matching_bracket_highlights(window, cx);
21926                if self.has_active_edit_prediction() {
21927                    self.update_visible_edit_prediction(window, cx);
21928                }
21929
21930                if let Some(buffer) = edited_buffer {
21931                    if buffer.read(cx).file().is_none() {
21932                        cx.emit(EditorEvent::TitleChanged);
21933                    }
21934
21935                    if self.project.is_some() {
21936                        let buffer_id = buffer.read(cx).remote_id();
21937                        self.register_buffer(buffer_id, cx);
21938                        self.update_lsp_data(Some(buffer_id), window, cx);
21939                        self.refresh_inlay_hints(
21940                            InlayHintRefreshReason::BufferEdited(buffer_id),
21941                            cx,
21942                        );
21943                    }
21944                }
21945
21946                cx.emit(EditorEvent::BufferEdited);
21947                cx.emit(SearchEvent::MatchesInvalidated);
21948
21949                let Some(project) = &self.project else { return };
21950                let (telemetry, is_via_ssh) = {
21951                    let project = project.read(cx);
21952                    let telemetry = project.client().telemetry().clone();
21953                    let is_via_ssh = project.is_via_remote_server();
21954                    (telemetry, is_via_ssh)
21955                };
21956                telemetry.log_edit_event("editor", is_via_ssh);
21957            }
21958            multi_buffer::Event::ExcerptsAdded {
21959                buffer,
21960                predecessor,
21961                excerpts,
21962            } => {
21963                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21964                let buffer_id = buffer.read(cx).remote_id();
21965                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21966                    && let Some(project) = &self.project
21967                {
21968                    update_uncommitted_diff_for_buffer(
21969                        cx.entity(),
21970                        project,
21971                        [buffer.clone()],
21972                        self.buffer.clone(),
21973                        cx,
21974                    )
21975                    .detach();
21976                }
21977                self.update_lsp_data(Some(buffer_id), window, cx);
21978                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21979                self.colorize_brackets(false, cx);
21980                cx.emit(EditorEvent::ExcerptsAdded {
21981                    buffer: buffer.clone(),
21982                    predecessor: *predecessor,
21983                    excerpts: excerpts.clone(),
21984                });
21985            }
21986            multi_buffer::Event::ExcerptsRemoved {
21987                ids,
21988                removed_buffer_ids,
21989            } => {
21990                if let Some(inlay_hints) = &mut self.inlay_hints {
21991                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21992                }
21993                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21994                for buffer_id in removed_buffer_ids {
21995                    self.registered_buffers.remove(buffer_id);
21996                }
21997                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21998                cx.emit(EditorEvent::ExcerptsRemoved {
21999                    ids: ids.clone(),
22000                    removed_buffer_ids: removed_buffer_ids.clone(),
22001                });
22002            }
22003            multi_buffer::Event::ExcerptsEdited {
22004                excerpt_ids,
22005                buffer_ids,
22006            } => {
22007                self.display_map.update(cx, |map, cx| {
22008                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22009                });
22010                cx.emit(EditorEvent::ExcerptsEdited {
22011                    ids: excerpt_ids.clone(),
22012                });
22013            }
22014            multi_buffer::Event::ExcerptsExpanded { ids } => {
22015                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22016                self.refresh_document_highlights(cx);
22017                for id in ids {
22018                    self.fetched_tree_sitter_chunks.remove(id);
22019                }
22020                self.colorize_brackets(false, cx);
22021                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22022            }
22023            multi_buffer::Event::Reparsed(buffer_id) => {
22024                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22025                self.refresh_selected_text_highlights(true, window, cx);
22026                self.colorize_brackets(true, cx);
22027                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22028
22029                cx.emit(EditorEvent::Reparsed(*buffer_id));
22030            }
22031            multi_buffer::Event::DiffHunksToggled => {
22032                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22033            }
22034            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22035                if !is_fresh_language {
22036                    self.registered_buffers.remove(&buffer_id);
22037                }
22038                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22039                cx.emit(EditorEvent::Reparsed(*buffer_id));
22040                cx.notify();
22041            }
22042            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22043            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22044            multi_buffer::Event::FileHandleChanged
22045            | multi_buffer::Event::Reloaded
22046            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22047            multi_buffer::Event::DiagnosticsUpdated => {
22048                self.update_diagnostics_state(window, cx);
22049            }
22050            _ => {}
22051        };
22052    }
22053
22054    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22055        if !self.diagnostics_enabled() {
22056            return;
22057        }
22058        self.refresh_active_diagnostics(cx);
22059        self.refresh_inline_diagnostics(true, window, cx);
22060        self.scrollbar_marker_state.dirty = true;
22061        cx.notify();
22062    }
22063
22064    pub fn start_temporary_diff_override(&mut self) {
22065        self.load_diff_task.take();
22066        self.temporary_diff_override = true;
22067    }
22068
22069    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22070        self.temporary_diff_override = false;
22071        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22072        self.buffer.update(cx, |buffer, cx| {
22073            buffer.set_all_diff_hunks_collapsed(cx);
22074        });
22075
22076        if let Some(project) = self.project.clone() {
22077            self.load_diff_task = Some(
22078                update_uncommitted_diff_for_buffer(
22079                    cx.entity(),
22080                    &project,
22081                    self.buffer.read(cx).all_buffers(),
22082                    self.buffer.clone(),
22083                    cx,
22084                )
22085                .shared(),
22086            );
22087        }
22088    }
22089
22090    fn on_display_map_changed(
22091        &mut self,
22092        _: Entity<DisplayMap>,
22093        _: &mut Window,
22094        cx: &mut Context<Self>,
22095    ) {
22096        cx.notify();
22097    }
22098
22099    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22100        if !self.mode.is_full() {
22101            return None;
22102        }
22103
22104        let theme_settings = theme::ThemeSettings::get_global(cx);
22105        let theme = cx.theme();
22106        let accent_colors = theme.accents().clone();
22107
22108        let accent_overrides = theme_settings
22109            .theme_overrides
22110            .get(theme.name.as_ref())
22111            .map(|theme_style| &theme_style.accents)
22112            .into_iter()
22113            .flatten()
22114            .chain(
22115                theme_settings
22116                    .experimental_theme_overrides
22117                    .as_ref()
22118                    .map(|overrides| &overrides.accents)
22119                    .into_iter()
22120                    .flatten(),
22121            )
22122            .flat_map(|accent| accent.0.clone())
22123            .collect();
22124
22125        Some(AccentData {
22126            colors: accent_colors,
22127            overrides: accent_overrides,
22128        })
22129    }
22130
22131    fn fetch_applicable_language_settings(
22132        &self,
22133        cx: &App,
22134    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22135        if !self.mode.is_full() {
22136            return HashMap::default();
22137        }
22138
22139        self.buffer().read(cx).all_buffers().into_iter().fold(
22140            HashMap::default(),
22141            |mut acc, buffer| {
22142                let buffer = buffer.read(cx);
22143                let language = buffer.language().map(|language| language.name());
22144                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22145                    let file = buffer.file();
22146                    v.insert(language_settings(language, file, cx).into_owned());
22147                }
22148                acc
22149            },
22150        )
22151    }
22152
22153    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22154        let new_language_settings = self.fetch_applicable_language_settings(cx);
22155        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22156        self.applicable_language_settings = new_language_settings;
22157
22158        let new_accents = self.fetch_accent_data(cx);
22159        let accents_changed = new_accents != self.accent_data;
22160        self.accent_data = new_accents;
22161
22162        if self.diagnostics_enabled() {
22163            let new_severity = EditorSettings::get_global(cx)
22164                .diagnostics_max_severity
22165                .unwrap_or(DiagnosticSeverity::Hint);
22166            self.set_max_diagnostics_severity(new_severity, cx);
22167        }
22168        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22169        self.update_edit_prediction_settings(cx);
22170        self.refresh_edit_prediction(true, false, window, cx);
22171        self.refresh_inline_values(cx);
22172        self.refresh_inlay_hints(
22173            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22174                self.selections.newest_anchor().head(),
22175                &self.buffer.read(cx).snapshot(cx),
22176                cx,
22177            )),
22178            cx,
22179        );
22180
22181        let old_cursor_shape = self.cursor_shape;
22182        let old_show_breadcrumbs = self.show_breadcrumbs;
22183
22184        {
22185            let editor_settings = EditorSettings::get_global(cx);
22186            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22187            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22188            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22189            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22190        }
22191
22192        if old_cursor_shape != self.cursor_shape {
22193            cx.emit(EditorEvent::CursorShapeChanged);
22194        }
22195
22196        if old_show_breadcrumbs != self.show_breadcrumbs {
22197            cx.emit(EditorEvent::BreadcrumbsChanged);
22198        }
22199
22200        let project_settings = ProjectSettings::get_global(cx);
22201        self.buffer_serialization = self
22202            .should_serialize_buffer()
22203            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22204
22205        if self.mode.is_full() {
22206            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22207            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22208            if self.show_inline_diagnostics != show_inline_diagnostics {
22209                self.show_inline_diagnostics = show_inline_diagnostics;
22210                self.refresh_inline_diagnostics(false, window, cx);
22211            }
22212
22213            if self.git_blame_inline_enabled != inline_blame_enabled {
22214                self.toggle_git_blame_inline_internal(false, window, cx);
22215            }
22216
22217            let minimap_settings = EditorSettings::get_global(cx).minimap;
22218            if self.minimap_visibility != MinimapVisibility::Disabled {
22219                if self.minimap_visibility.settings_visibility()
22220                    != minimap_settings.minimap_enabled()
22221                {
22222                    self.set_minimap_visibility(
22223                        MinimapVisibility::for_mode(self.mode(), cx),
22224                        window,
22225                        cx,
22226                    );
22227                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22228                    minimap_entity.update(cx, |minimap_editor, cx| {
22229                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22230                    })
22231                }
22232            }
22233
22234            if language_settings_changed || accents_changed {
22235                self.colorize_brackets(true, cx);
22236            }
22237
22238            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22239                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22240            }) {
22241                if !inlay_splice.is_empty() {
22242                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22243                }
22244                self.refresh_colors_for_visible_range(None, window, cx);
22245            }
22246        }
22247
22248        cx.notify();
22249    }
22250
22251    pub fn set_searchable(&mut self, searchable: bool) {
22252        self.searchable = searchable;
22253    }
22254
22255    pub fn searchable(&self) -> bool {
22256        self.searchable
22257    }
22258
22259    pub fn open_excerpts_in_split(
22260        &mut self,
22261        _: &OpenExcerptsSplit,
22262        window: &mut Window,
22263        cx: &mut Context<Self>,
22264    ) {
22265        self.open_excerpts_common(None, true, window, cx)
22266    }
22267
22268    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22269        self.open_excerpts_common(None, false, window, cx)
22270    }
22271
22272    fn open_excerpts_common(
22273        &mut self,
22274        jump_data: Option<JumpData>,
22275        split: bool,
22276        window: &mut Window,
22277        cx: &mut Context<Self>,
22278    ) {
22279        let Some(workspace) = self.workspace() else {
22280            cx.propagate();
22281            return;
22282        };
22283
22284        if self.buffer.read(cx).is_singleton() {
22285            cx.propagate();
22286            return;
22287        }
22288
22289        let mut new_selections_by_buffer = HashMap::default();
22290        match &jump_data {
22291            Some(JumpData::MultiBufferPoint {
22292                excerpt_id,
22293                position,
22294                anchor,
22295                line_offset_from_top,
22296            }) => {
22297                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22298                if let Some(buffer) = multi_buffer_snapshot
22299                    .buffer_id_for_excerpt(*excerpt_id)
22300                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22301                {
22302                    let buffer_snapshot = buffer.read(cx).snapshot();
22303                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22304                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22305                    } else {
22306                        buffer_snapshot.clip_point(*position, Bias::Left)
22307                    };
22308                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22309                    new_selections_by_buffer.insert(
22310                        buffer,
22311                        (
22312                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22313                            Some(*line_offset_from_top),
22314                        ),
22315                    );
22316                }
22317            }
22318            Some(JumpData::MultiBufferRow {
22319                row,
22320                line_offset_from_top,
22321            }) => {
22322                let point = MultiBufferPoint::new(row.0, 0);
22323                if let Some((buffer, buffer_point, _)) =
22324                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22325                {
22326                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22327                    new_selections_by_buffer
22328                        .entry(buffer)
22329                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22330                        .0
22331                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22332                }
22333            }
22334            None => {
22335                let selections = self
22336                    .selections
22337                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22338                let multi_buffer = self.buffer.read(cx);
22339                for selection in selections {
22340                    for (snapshot, range, _, anchor) in multi_buffer
22341                        .snapshot(cx)
22342                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22343                    {
22344                        if let Some(anchor) = anchor {
22345                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22346                            else {
22347                                continue;
22348                            };
22349                            let offset = text::ToOffset::to_offset(
22350                                &anchor.text_anchor,
22351                                &buffer_handle.read(cx).snapshot(),
22352                            );
22353                            let range = BufferOffset(offset)..BufferOffset(offset);
22354                            new_selections_by_buffer
22355                                .entry(buffer_handle)
22356                                .or_insert((Vec::new(), None))
22357                                .0
22358                                .push(range)
22359                        } else {
22360                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22361                            else {
22362                                continue;
22363                            };
22364                            new_selections_by_buffer
22365                                .entry(buffer_handle)
22366                                .or_insert((Vec::new(), None))
22367                                .0
22368                                .push(range)
22369                        }
22370                    }
22371                }
22372            }
22373        }
22374
22375        new_selections_by_buffer
22376            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22377
22378        if new_selections_by_buffer.is_empty() {
22379            return;
22380        }
22381
22382        // We defer the pane interaction because we ourselves are a workspace item
22383        // and activating a new item causes the pane to call a method on us reentrantly,
22384        // which panics if we're on the stack.
22385        window.defer(cx, move |window, cx| {
22386            workspace.update(cx, |workspace, cx| {
22387                let pane = if split {
22388                    workspace.adjacent_pane(window, cx)
22389                } else {
22390                    workspace.active_pane().clone()
22391                };
22392
22393                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22394                    let buffer_read = buffer.read(cx);
22395                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22396                        (true, project::File::from_dyn(Some(file)).is_some())
22397                    } else {
22398                        (false, false)
22399                    };
22400
22401                    // If project file is none workspace.open_project_item will fail to open the excerpt
22402                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22403                    // so we check if there's a tab match in that case first
22404                    let editor = (!has_file || !is_project_file)
22405                        .then(|| {
22406                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22407                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22408                            // Instead, we try to activate the existing editor in the pane first.
22409                            let (editor, pane_item_index, pane_item_id) =
22410                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22411                                    let editor = item.downcast::<Editor>()?;
22412                                    let singleton_buffer =
22413                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22414                                    if singleton_buffer == buffer {
22415                                        Some((editor, i, item.item_id()))
22416                                    } else {
22417                                        None
22418                                    }
22419                                })?;
22420                            pane.update(cx, |pane, cx| {
22421                                pane.activate_item(pane_item_index, true, true, window, cx);
22422                                if !PreviewTabsSettings::get_global(cx)
22423                                    .enable_preview_from_multibuffer
22424                                {
22425                                    pane.unpreview_item_if_preview(pane_item_id);
22426                                }
22427                            });
22428                            Some(editor)
22429                        })
22430                        .flatten()
22431                        .unwrap_or_else(|| {
22432                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22433                                .enable_keep_preview_on_code_navigation;
22434                            let allow_new_preview =
22435                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22436                            workspace.open_project_item::<Self>(
22437                                pane.clone(),
22438                                buffer,
22439                                true,
22440                                true,
22441                                keep_old_preview,
22442                                allow_new_preview,
22443                                window,
22444                                cx,
22445                            )
22446                        });
22447
22448                    editor.update(cx, |editor, cx| {
22449                        if has_file && !is_project_file {
22450                            editor.set_read_only(true);
22451                        }
22452                        let autoscroll = match scroll_offset {
22453                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22454                            None => Autoscroll::newest(),
22455                        };
22456                        let nav_history = editor.nav_history.take();
22457                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22458                        let Some((&excerpt_id, _, buffer_snapshot)) =
22459                            multibuffer_snapshot.as_singleton()
22460                        else {
22461                            return;
22462                        };
22463                        editor.change_selections(
22464                            SelectionEffects::scroll(autoscroll),
22465                            window,
22466                            cx,
22467                            |s| {
22468                                s.select_ranges(ranges.into_iter().map(|range| {
22469                                    let range = buffer_snapshot.anchor_before(range.start)
22470                                        ..buffer_snapshot.anchor_after(range.end);
22471                                    multibuffer_snapshot
22472                                        .anchor_range_in_excerpt(excerpt_id, range)
22473                                        .unwrap()
22474                                }));
22475                            },
22476                        );
22477                        editor.nav_history = nav_history;
22478                    });
22479                }
22480            })
22481        });
22482    }
22483
22484    // Allow opening excerpts for buffers that either belong to the current project
22485    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22486    // are also supported so tests and other in-memory views keep working.
22487    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22488        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22489    }
22490
22491    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22492        let snapshot = self.buffer.read(cx).read(cx);
22493        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22494        Some(
22495            ranges
22496                .iter()
22497                .map(move |range| {
22498                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22499                })
22500                .collect(),
22501        )
22502    }
22503
22504    fn selection_replacement_ranges(
22505        &self,
22506        range: Range<MultiBufferOffsetUtf16>,
22507        cx: &mut App,
22508    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22509        let selections = self
22510            .selections
22511            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22512        let newest_selection = selections
22513            .iter()
22514            .max_by_key(|selection| selection.id)
22515            .unwrap();
22516        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22517        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22518        let snapshot = self.buffer.read(cx).read(cx);
22519        selections
22520            .into_iter()
22521            .map(|mut selection| {
22522                selection.start.0.0 =
22523                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22524                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22525                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22526                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22527            })
22528            .collect()
22529    }
22530
22531    fn report_editor_event(
22532        &self,
22533        reported_event: ReportEditorEvent,
22534        file_extension: Option<String>,
22535        cx: &App,
22536    ) {
22537        if cfg!(any(test, feature = "test-support")) {
22538            return;
22539        }
22540
22541        let Some(project) = &self.project else { return };
22542
22543        // If None, we are in a file without an extension
22544        let file = self
22545            .buffer
22546            .read(cx)
22547            .as_singleton()
22548            .and_then(|b| b.read(cx).file());
22549        let file_extension = file_extension.or(file
22550            .as_ref()
22551            .and_then(|file| Path::new(file.file_name(cx)).extension())
22552            .and_then(|e| e.to_str())
22553            .map(|a| a.to_string()));
22554
22555        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22556            .map(|vim_mode| vim_mode.0)
22557            .unwrap_or(false);
22558
22559        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22560        let copilot_enabled = edit_predictions_provider
22561            == language::language_settings::EditPredictionProvider::Copilot;
22562        let copilot_enabled_for_language = self
22563            .buffer
22564            .read(cx)
22565            .language_settings(cx)
22566            .show_edit_predictions;
22567
22568        let project = project.read(cx);
22569        let event_type = reported_event.event_type();
22570
22571        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22572            telemetry::event!(
22573                event_type,
22574                type = if auto_saved {"autosave"} else {"manual"},
22575                file_extension,
22576                vim_mode,
22577                copilot_enabled,
22578                copilot_enabled_for_language,
22579                edit_predictions_provider,
22580                is_via_ssh = project.is_via_remote_server(),
22581            );
22582        } else {
22583            telemetry::event!(
22584                event_type,
22585                file_extension,
22586                vim_mode,
22587                copilot_enabled,
22588                copilot_enabled_for_language,
22589                edit_predictions_provider,
22590                is_via_ssh = project.is_via_remote_server(),
22591            );
22592        };
22593    }
22594
22595    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22596    /// with each line being an array of {text, highlight} objects.
22597    fn copy_highlight_json(
22598        &mut self,
22599        _: &CopyHighlightJson,
22600        window: &mut Window,
22601        cx: &mut Context<Self>,
22602    ) {
22603        #[derive(Serialize)]
22604        struct Chunk<'a> {
22605            text: String,
22606            highlight: Option<&'a str>,
22607        }
22608
22609        let snapshot = self.buffer.read(cx).snapshot(cx);
22610        let range = self
22611            .selected_text_range(false, window, cx)
22612            .and_then(|selection| {
22613                if selection.range.is_empty() {
22614                    None
22615                } else {
22616                    Some(
22617                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22618                            selection.range.start,
22619                        )))
22620                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22621                                selection.range.end,
22622                            ))),
22623                    )
22624                }
22625            })
22626            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22627
22628        let chunks = snapshot.chunks(range, true);
22629        let mut lines = Vec::new();
22630        let mut line: VecDeque<Chunk> = VecDeque::new();
22631
22632        let Some(style) = self.style.as_ref() else {
22633            return;
22634        };
22635
22636        for chunk in chunks {
22637            let highlight = chunk
22638                .syntax_highlight_id
22639                .and_then(|id| id.name(&style.syntax));
22640            let mut chunk_lines = chunk.text.split('\n').peekable();
22641            while let Some(text) = chunk_lines.next() {
22642                let mut merged_with_last_token = false;
22643                if let Some(last_token) = line.back_mut()
22644                    && last_token.highlight == highlight
22645                {
22646                    last_token.text.push_str(text);
22647                    merged_with_last_token = true;
22648                }
22649
22650                if !merged_with_last_token {
22651                    line.push_back(Chunk {
22652                        text: text.into(),
22653                        highlight,
22654                    });
22655                }
22656
22657                if chunk_lines.peek().is_some() {
22658                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22659                        line.pop_front();
22660                    }
22661                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22662                        line.pop_back();
22663                    }
22664
22665                    lines.push(mem::take(&mut line));
22666                }
22667            }
22668        }
22669
22670        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22671            return;
22672        };
22673        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22674    }
22675
22676    pub fn open_context_menu(
22677        &mut self,
22678        _: &OpenContextMenu,
22679        window: &mut Window,
22680        cx: &mut Context<Self>,
22681    ) {
22682        self.request_autoscroll(Autoscroll::newest(), cx);
22683        let position = self
22684            .selections
22685            .newest_display(&self.display_snapshot(cx))
22686            .start;
22687        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22688    }
22689
22690    pub fn replay_insert_event(
22691        &mut self,
22692        text: &str,
22693        relative_utf16_range: Option<Range<isize>>,
22694        window: &mut Window,
22695        cx: &mut Context<Self>,
22696    ) {
22697        if !self.input_enabled {
22698            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22699            return;
22700        }
22701        if let Some(relative_utf16_range) = relative_utf16_range {
22702            let selections = self
22703                .selections
22704                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22705            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22706                let new_ranges = selections.into_iter().map(|range| {
22707                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22708                        range
22709                            .head()
22710                            .0
22711                            .0
22712                            .saturating_add_signed(relative_utf16_range.start),
22713                    ));
22714                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22715                        range
22716                            .head()
22717                            .0
22718                            .0
22719                            .saturating_add_signed(relative_utf16_range.end),
22720                    ));
22721                    start..end
22722                });
22723                s.select_ranges(new_ranges);
22724            });
22725        }
22726
22727        self.handle_input(text, window, cx);
22728    }
22729
22730    pub fn is_focused(&self, window: &Window) -> bool {
22731        self.focus_handle.is_focused(window)
22732    }
22733
22734    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22735        cx.emit(EditorEvent::Focused);
22736
22737        if let Some(descendant) = self
22738            .last_focused_descendant
22739            .take()
22740            .and_then(|descendant| descendant.upgrade())
22741        {
22742            window.focus(&descendant, cx);
22743        } else {
22744            if let Some(blame) = self.blame.as_ref() {
22745                blame.update(cx, GitBlame::focus)
22746            }
22747
22748            self.blink_manager.update(cx, BlinkManager::enable);
22749            self.show_cursor_names(window, cx);
22750            self.buffer.update(cx, |buffer, cx| {
22751                buffer.finalize_last_transaction(cx);
22752                if self.leader_id.is_none() {
22753                    buffer.set_active_selections(
22754                        &self.selections.disjoint_anchors_arc(),
22755                        self.selections.line_mode(),
22756                        self.cursor_shape,
22757                        cx,
22758                    );
22759                }
22760            });
22761
22762            if let Some(position_map) = self.last_position_map.clone() {
22763                EditorElement::mouse_moved(
22764                    self,
22765                    &MouseMoveEvent {
22766                        position: window.mouse_position(),
22767                        pressed_button: None,
22768                        modifiers: window.modifiers(),
22769                    },
22770                    &position_map,
22771                    window,
22772                    cx,
22773                );
22774            }
22775        }
22776    }
22777
22778    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22779        cx.emit(EditorEvent::FocusedIn)
22780    }
22781
22782    fn handle_focus_out(
22783        &mut self,
22784        event: FocusOutEvent,
22785        _window: &mut Window,
22786        cx: &mut Context<Self>,
22787    ) {
22788        if event.blurred != self.focus_handle {
22789            self.last_focused_descendant = Some(event.blurred);
22790        }
22791        self.selection_drag_state = SelectionDragState::None;
22792        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22793    }
22794
22795    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22796        self.blink_manager.update(cx, BlinkManager::disable);
22797        self.buffer
22798            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22799
22800        if let Some(blame) = self.blame.as_ref() {
22801            blame.update(cx, GitBlame::blur)
22802        }
22803        if !self.hover_state.focused(window, cx) {
22804            hide_hover(self, cx);
22805        }
22806        if !self
22807            .context_menu
22808            .borrow()
22809            .as_ref()
22810            .is_some_and(|context_menu| context_menu.focused(window, cx))
22811        {
22812            self.hide_context_menu(window, cx);
22813        }
22814        self.take_active_edit_prediction(cx);
22815        cx.emit(EditorEvent::Blurred);
22816        cx.notify();
22817    }
22818
22819    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22820        let mut pending: String = window
22821            .pending_input_keystrokes()
22822            .into_iter()
22823            .flatten()
22824            .filter_map(|keystroke| keystroke.key_char.clone())
22825            .collect();
22826
22827        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22828            pending = "".to_string();
22829        }
22830
22831        let existing_pending = self
22832            .text_highlights::<PendingInput>(cx)
22833            .map(|(_, ranges)| ranges.to_vec());
22834        if existing_pending.is_none() && pending.is_empty() {
22835            return;
22836        }
22837        let transaction =
22838            self.transact(window, cx, |this, window, cx| {
22839                let selections = this
22840                    .selections
22841                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22842                let edits = selections
22843                    .iter()
22844                    .map(|selection| (selection.end..selection.end, pending.clone()));
22845                this.edit(edits, cx);
22846                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22847                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22848                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22849                    }));
22850                });
22851                if let Some(existing_ranges) = existing_pending {
22852                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22853                    this.edit(edits, cx);
22854                }
22855            });
22856
22857        let snapshot = self.snapshot(window, cx);
22858        let ranges = self
22859            .selections
22860            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22861            .into_iter()
22862            .map(|selection| {
22863                snapshot.buffer_snapshot().anchor_after(selection.end)
22864                    ..snapshot
22865                        .buffer_snapshot()
22866                        .anchor_before(selection.end + pending.len())
22867            })
22868            .collect();
22869
22870        if pending.is_empty() {
22871            self.clear_highlights::<PendingInput>(cx);
22872        } else {
22873            self.highlight_text::<PendingInput>(
22874                ranges,
22875                HighlightStyle {
22876                    underline: Some(UnderlineStyle {
22877                        thickness: px(1.),
22878                        color: None,
22879                        wavy: false,
22880                    }),
22881                    ..Default::default()
22882                },
22883                cx,
22884            );
22885        }
22886
22887        self.ime_transaction = self.ime_transaction.or(transaction);
22888        if let Some(transaction) = self.ime_transaction {
22889            self.buffer.update(cx, |buffer, cx| {
22890                buffer.group_until_transaction(transaction, cx);
22891            });
22892        }
22893
22894        if self.text_highlights::<PendingInput>(cx).is_none() {
22895            self.ime_transaction.take();
22896        }
22897    }
22898
22899    pub fn register_action_renderer(
22900        &mut self,
22901        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22902    ) -> Subscription {
22903        let id = self.next_editor_action_id.post_inc();
22904        self.editor_actions
22905            .borrow_mut()
22906            .insert(id, Box::new(listener));
22907
22908        let editor_actions = self.editor_actions.clone();
22909        Subscription::new(move || {
22910            editor_actions.borrow_mut().remove(&id);
22911        })
22912    }
22913
22914    pub fn register_action<A: Action>(
22915        &mut self,
22916        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22917    ) -> Subscription {
22918        let id = self.next_editor_action_id.post_inc();
22919        let listener = Arc::new(listener);
22920        self.editor_actions.borrow_mut().insert(
22921            id,
22922            Box::new(move |_, window, _| {
22923                let listener = listener.clone();
22924                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22925                    let action = action.downcast_ref().unwrap();
22926                    if phase == DispatchPhase::Bubble {
22927                        listener(action, window, cx)
22928                    }
22929                })
22930            }),
22931        );
22932
22933        let editor_actions = self.editor_actions.clone();
22934        Subscription::new(move || {
22935            editor_actions.borrow_mut().remove(&id);
22936        })
22937    }
22938
22939    pub fn file_header_size(&self) -> u32 {
22940        FILE_HEADER_HEIGHT
22941    }
22942
22943    pub fn restore(
22944        &mut self,
22945        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22946        window: &mut Window,
22947        cx: &mut Context<Self>,
22948    ) {
22949        self.buffer().update(cx, |multi_buffer, cx| {
22950            for (buffer_id, changes) in revert_changes {
22951                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22952                    buffer.update(cx, |buffer, cx| {
22953                        buffer.edit(
22954                            changes
22955                                .into_iter()
22956                                .map(|(range, text)| (range, text.to_string())),
22957                            None,
22958                            cx,
22959                        );
22960                    });
22961                }
22962            }
22963        });
22964        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22965            selections.refresh()
22966        });
22967    }
22968
22969    pub fn to_pixel_point(
22970        &mut self,
22971        source: multi_buffer::Anchor,
22972        editor_snapshot: &EditorSnapshot,
22973        window: &mut Window,
22974        cx: &App,
22975    ) -> Option<gpui::Point<Pixels>> {
22976        let source_point = source.to_display_point(editor_snapshot);
22977        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
22978    }
22979
22980    pub fn display_to_pixel_point(
22981        &mut self,
22982        source: DisplayPoint,
22983        editor_snapshot: &EditorSnapshot,
22984        window: &mut Window,
22985        cx: &App,
22986    ) -> Option<gpui::Point<Pixels>> {
22987        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
22988        let text_layout_details = self.text_layout_details(window);
22989        let scroll_top = text_layout_details
22990            .scroll_anchor
22991            .scroll_position(editor_snapshot)
22992            .y;
22993
22994        if source.row().as_f64() < scroll_top.floor() {
22995            return None;
22996        }
22997        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22998        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22999        Some(gpui::Point::new(source_x, source_y))
23000    }
23001
23002    pub fn has_visible_completions_menu(&self) -> bool {
23003        !self.edit_prediction_preview_is_active()
23004            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23005                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23006            })
23007    }
23008
23009    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23010        if self.mode.is_minimap() {
23011            return;
23012        }
23013        self.addons
23014            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23015    }
23016
23017    pub fn unregister_addon<T: Addon>(&mut self) {
23018        self.addons.remove(&std::any::TypeId::of::<T>());
23019    }
23020
23021    pub fn addon<T: Addon>(&self) -> Option<&T> {
23022        let type_id = std::any::TypeId::of::<T>();
23023        self.addons
23024            .get(&type_id)
23025            .and_then(|item| item.to_any().downcast_ref::<T>())
23026    }
23027
23028    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23029        let type_id = std::any::TypeId::of::<T>();
23030        self.addons
23031            .get_mut(&type_id)
23032            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23033    }
23034
23035    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23036        let text_layout_details = self.text_layout_details(window);
23037        let style = &text_layout_details.editor_style;
23038        let font_id = window.text_system().resolve_font(&style.text.font());
23039        let font_size = style.text.font_size.to_pixels(window.rem_size());
23040        let line_height = style.text.line_height_in_pixels(window.rem_size());
23041        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23042        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23043
23044        CharacterDimensions {
23045            em_width,
23046            em_advance,
23047            line_height,
23048        }
23049    }
23050
23051    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23052        self.load_diff_task.clone()
23053    }
23054
23055    fn read_metadata_from_db(
23056        &mut self,
23057        item_id: u64,
23058        workspace_id: WorkspaceId,
23059        window: &mut Window,
23060        cx: &mut Context<Editor>,
23061    ) {
23062        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23063            && !self.mode.is_minimap()
23064            && WorkspaceSettings::get(None, cx).restore_on_startup
23065                != RestoreOnStartupBehavior::EmptyTab
23066        {
23067            let buffer_snapshot = OnceCell::new();
23068
23069            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23070                && !folds.is_empty()
23071            {
23072                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23073                self.fold_ranges(
23074                    folds
23075                        .into_iter()
23076                        .map(|(start, end)| {
23077                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23078                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23079                        })
23080                        .collect(),
23081                    false,
23082                    window,
23083                    cx,
23084                );
23085            }
23086
23087            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23088                && !selections.is_empty()
23089            {
23090                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23091                // skip adding the initial selection to selection history
23092                self.selection_history.mode = SelectionHistoryMode::Skipping;
23093                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23094                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23095                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23096                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23097                    }));
23098                });
23099                self.selection_history.mode = SelectionHistoryMode::Normal;
23100            };
23101        }
23102
23103        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23104    }
23105
23106    fn update_lsp_data(
23107        &mut self,
23108        for_buffer: Option<BufferId>,
23109        window: &mut Window,
23110        cx: &mut Context<'_, Self>,
23111    ) {
23112        self.pull_diagnostics(for_buffer, window, cx);
23113        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23114    }
23115
23116    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23117        if self.ignore_lsp_data() {
23118            return;
23119        }
23120        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23121            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23122        }
23123    }
23124
23125    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23126        if self.ignore_lsp_data() {
23127            return;
23128        }
23129
23130        if !self.registered_buffers.contains_key(&buffer_id)
23131            && let Some(project) = self.project.as_ref()
23132        {
23133            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23134                project.update(cx, |project, cx| {
23135                    self.registered_buffers.insert(
23136                        buffer_id,
23137                        project.register_buffer_with_language_servers(&buffer, cx),
23138                    );
23139                });
23140            } else {
23141                self.registered_buffers.remove(&buffer_id);
23142            }
23143        }
23144    }
23145
23146    fn ignore_lsp_data(&self) -> bool {
23147        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23148        // skip any LSP updates for it.
23149        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23150    }
23151
23152    fn create_style(&self, cx: &App) -> EditorStyle {
23153        let settings = ThemeSettings::get_global(cx);
23154
23155        let mut text_style = match self.mode {
23156            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23157                color: cx.theme().colors().editor_foreground,
23158                font_family: settings.ui_font.family.clone(),
23159                font_features: settings.ui_font.features.clone(),
23160                font_fallbacks: settings.ui_font.fallbacks.clone(),
23161                font_size: rems(0.875).into(),
23162                font_weight: settings.ui_font.weight,
23163                line_height: relative(settings.buffer_line_height.value()),
23164                ..Default::default()
23165            },
23166            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23167                color: cx.theme().colors().editor_foreground,
23168                font_family: settings.buffer_font.family.clone(),
23169                font_features: settings.buffer_font.features.clone(),
23170                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23171                font_size: settings.buffer_font_size(cx).into(),
23172                font_weight: settings.buffer_font.weight,
23173                line_height: relative(settings.buffer_line_height.value()),
23174                ..Default::default()
23175            },
23176        };
23177        if let Some(text_style_refinement) = &self.text_style_refinement {
23178            text_style.refine(text_style_refinement)
23179        }
23180
23181        let background = match self.mode {
23182            EditorMode::SingleLine => cx.theme().system().transparent,
23183            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23184            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23185            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23186        };
23187
23188        EditorStyle {
23189            background,
23190            border: cx.theme().colors().border,
23191            local_player: cx.theme().players().local(),
23192            text: text_style,
23193            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23194            syntax: cx.theme().syntax().clone(),
23195            status: cx.theme().status().clone(),
23196            inlay_hints_style: make_inlay_hints_style(cx),
23197            edit_prediction_styles: make_suggestion_styles(cx),
23198            unnecessary_code_fade: settings.unnecessary_code_fade,
23199            show_underlines: self.diagnostics_enabled(),
23200        }
23201    }
23202    fn breadcrumbs_inner(&self, variant: &Theme, cx: &App) -> Option<Vec<BreadcrumbText>> {
23203        let cursor = self.selections.newest_anchor().head();
23204        let multibuffer = self.buffer().read(cx);
23205        let is_singleton = multibuffer.is_singleton();
23206        let (buffer_id, symbols) = multibuffer
23207            .read(cx)
23208            .symbols_containing(cursor, Some(variant.syntax()))?;
23209        let buffer = multibuffer.buffer(buffer_id)?;
23210
23211        let buffer = buffer.read(cx);
23212        let settings = ThemeSettings::get_global(cx);
23213        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
23214        let mut breadcrumbs = if is_singleton {
23215            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
23216                buffer
23217                    .snapshot()
23218                    .resolve_file_path(
23219                        self.project
23220                            .as_ref()
23221                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
23222                            .unwrap_or_default(),
23223                        cx,
23224                    )
23225                    .unwrap_or_else(|| {
23226                        if multibuffer.is_singleton() {
23227                            multibuffer.title(cx).to_string()
23228                        } else {
23229                            "untitled".to_string()
23230                        }
23231                    })
23232            });
23233            vec![BreadcrumbText {
23234                text,
23235                highlights: None,
23236                font: Some(settings.buffer_font.clone()),
23237            }]
23238        } else {
23239            vec![]
23240        };
23241
23242        breadcrumbs.extend(symbols.into_iter().map(|symbol| BreadcrumbText {
23243            text: symbol.text,
23244            highlights: Some(symbol.highlight_ranges),
23245            font: Some(settings.buffer_font.clone()),
23246        }));
23247        Some(breadcrumbs)
23248    }
23249}
23250
23251fn edit_for_markdown_paste<'a>(
23252    buffer: &MultiBufferSnapshot,
23253    range: Range<MultiBufferOffset>,
23254    to_insert: &'a str,
23255    url: Option<url::Url>,
23256) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23257    if url.is_none() {
23258        return (range, Cow::Borrowed(to_insert));
23259    };
23260
23261    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23262
23263    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23264        Cow::Borrowed(to_insert)
23265    } else {
23266        Cow::Owned(format!("[{old_text}]({to_insert})"))
23267    };
23268    (range, new_text)
23269}
23270
23271fn process_completion_for_edit(
23272    completion: &Completion,
23273    intent: CompletionIntent,
23274    buffer: &Entity<Buffer>,
23275    cursor_position: &text::Anchor,
23276    cx: &mut Context<Editor>,
23277) -> CompletionEdit {
23278    let buffer = buffer.read(cx);
23279    let buffer_snapshot = buffer.snapshot();
23280    let (snippet, new_text) = if completion.is_snippet() {
23281        let mut snippet_source = completion.new_text.clone();
23282        // Workaround for typescript language server issues so that methods don't expand within
23283        // strings and functions with type expressions. The previous point is used because the query
23284        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23285        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23286        let previous_point = if previous_point.column > 0 {
23287            cursor_position.to_previous_offset(&buffer_snapshot)
23288        } else {
23289            cursor_position.to_offset(&buffer_snapshot)
23290        };
23291        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23292            && scope.prefers_label_for_snippet_in_completion()
23293            && let Some(label) = completion.label()
23294            && matches!(
23295                completion.kind(),
23296                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23297            )
23298        {
23299            snippet_source = label;
23300        }
23301        match Snippet::parse(&snippet_source).log_err() {
23302            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23303            None => (None, completion.new_text.clone()),
23304        }
23305    } else {
23306        (None, completion.new_text.clone())
23307    };
23308
23309    let mut range_to_replace = {
23310        let replace_range = &completion.replace_range;
23311        if let CompletionSource::Lsp {
23312            insert_range: Some(insert_range),
23313            ..
23314        } = &completion.source
23315        {
23316            debug_assert_eq!(
23317                insert_range.start, replace_range.start,
23318                "insert_range and replace_range should start at the same position"
23319            );
23320            debug_assert!(
23321                insert_range
23322                    .start
23323                    .cmp(cursor_position, &buffer_snapshot)
23324                    .is_le(),
23325                "insert_range should start before or at cursor position"
23326            );
23327            debug_assert!(
23328                replace_range
23329                    .start
23330                    .cmp(cursor_position, &buffer_snapshot)
23331                    .is_le(),
23332                "replace_range should start before or at cursor position"
23333            );
23334
23335            let should_replace = match intent {
23336                CompletionIntent::CompleteWithInsert => false,
23337                CompletionIntent::CompleteWithReplace => true,
23338                CompletionIntent::Complete | CompletionIntent::Compose => {
23339                    let insert_mode =
23340                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23341                            .completions
23342                            .lsp_insert_mode;
23343                    match insert_mode {
23344                        LspInsertMode::Insert => false,
23345                        LspInsertMode::Replace => true,
23346                        LspInsertMode::ReplaceSubsequence => {
23347                            let mut text_to_replace = buffer.chars_for_range(
23348                                buffer.anchor_before(replace_range.start)
23349                                    ..buffer.anchor_after(replace_range.end),
23350                            );
23351                            let mut current_needle = text_to_replace.next();
23352                            for haystack_ch in completion.label.text.chars() {
23353                                if let Some(needle_ch) = current_needle
23354                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23355                                {
23356                                    current_needle = text_to_replace.next();
23357                                }
23358                            }
23359                            current_needle.is_none()
23360                        }
23361                        LspInsertMode::ReplaceSuffix => {
23362                            if replace_range
23363                                .end
23364                                .cmp(cursor_position, &buffer_snapshot)
23365                                .is_gt()
23366                            {
23367                                let range_after_cursor = *cursor_position..replace_range.end;
23368                                let text_after_cursor = buffer
23369                                    .text_for_range(
23370                                        buffer.anchor_before(range_after_cursor.start)
23371                                            ..buffer.anchor_after(range_after_cursor.end),
23372                                    )
23373                                    .collect::<String>()
23374                                    .to_ascii_lowercase();
23375                                completion
23376                                    .label
23377                                    .text
23378                                    .to_ascii_lowercase()
23379                                    .ends_with(&text_after_cursor)
23380                            } else {
23381                                true
23382                            }
23383                        }
23384                    }
23385                }
23386            };
23387
23388            if should_replace {
23389                replace_range.clone()
23390            } else {
23391                insert_range.clone()
23392            }
23393        } else {
23394            replace_range.clone()
23395        }
23396    };
23397
23398    if range_to_replace
23399        .end
23400        .cmp(cursor_position, &buffer_snapshot)
23401        .is_lt()
23402    {
23403        range_to_replace.end = *cursor_position;
23404    }
23405
23406    let replace_range = range_to_replace.to_offset(buffer);
23407    CompletionEdit {
23408        new_text,
23409        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23410        snippet,
23411    }
23412}
23413
23414struct CompletionEdit {
23415    new_text: String,
23416    replace_range: Range<BufferOffset>,
23417    snippet: Option<Snippet>,
23418}
23419
23420fn comment_delimiter_for_newline(
23421    start_point: &Point,
23422    buffer: &MultiBufferSnapshot,
23423    language: &LanguageScope,
23424) -> Option<Arc<str>> {
23425    let delimiters = language.line_comment_prefixes();
23426    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
23427    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23428
23429    let num_of_whitespaces = snapshot
23430        .chars_for_range(range.clone())
23431        .take_while(|c| c.is_whitespace())
23432        .count();
23433    let comment_candidate = snapshot
23434        .chars_for_range(range.clone())
23435        .skip(num_of_whitespaces)
23436        .take(max_len_of_delimiter)
23437        .collect::<String>();
23438    let (delimiter, trimmed_len) = delimiters
23439        .iter()
23440        .filter_map(|delimiter| {
23441            let prefix = delimiter.trim_end();
23442            if comment_candidate.starts_with(prefix) {
23443                Some((delimiter, prefix.len()))
23444            } else {
23445                None
23446            }
23447        })
23448        .max_by_key(|(_, len)| *len)?;
23449
23450    if let Some(BlockCommentConfig {
23451        start: block_start, ..
23452    }) = language.block_comment()
23453    {
23454        let block_start_trimmed = block_start.trim_end();
23455        if block_start_trimmed.starts_with(delimiter.trim_end()) {
23456            let line_content = snapshot
23457                .chars_for_range(range)
23458                .skip(num_of_whitespaces)
23459                .take(block_start_trimmed.len())
23460                .collect::<String>();
23461
23462            if line_content.starts_with(block_start_trimmed) {
23463                return None;
23464            }
23465        }
23466    }
23467
23468    let cursor_is_placed_after_comment_marker =
23469        num_of_whitespaces + trimmed_len <= start_point.column as usize;
23470    if cursor_is_placed_after_comment_marker {
23471        Some(delimiter.clone())
23472    } else {
23473        None
23474    }
23475}
23476
23477fn documentation_delimiter_for_newline(
23478    start_point: &Point,
23479    buffer: &MultiBufferSnapshot,
23480    language: &LanguageScope,
23481    newline_config: &mut NewlineConfig,
23482) -> Option<Arc<str>> {
23483    let BlockCommentConfig {
23484        start: start_tag,
23485        end: end_tag,
23486        prefix: delimiter,
23487        tab_size: len,
23488    } = language.documentation_comment()?;
23489    let is_within_block_comment = buffer
23490        .language_scope_at(*start_point)
23491        .is_some_and(|scope| scope.override_name() == Some("comment"));
23492    if !is_within_block_comment {
23493        return None;
23494    }
23495
23496    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23497
23498    let num_of_whitespaces = snapshot
23499        .chars_for_range(range.clone())
23500        .take_while(|c| c.is_whitespace())
23501        .count();
23502
23503    // 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.
23504    let column = start_point.column;
23505    let cursor_is_after_start_tag = {
23506        let start_tag_len = start_tag.len();
23507        let start_tag_line = snapshot
23508            .chars_for_range(range.clone())
23509            .skip(num_of_whitespaces)
23510            .take(start_tag_len)
23511            .collect::<String>();
23512        if start_tag_line.starts_with(start_tag.as_ref()) {
23513            num_of_whitespaces + start_tag_len <= column as usize
23514        } else {
23515            false
23516        }
23517    };
23518
23519    let cursor_is_after_delimiter = {
23520        let delimiter_trim = delimiter.trim_end();
23521        let delimiter_line = snapshot
23522            .chars_for_range(range.clone())
23523            .skip(num_of_whitespaces)
23524            .take(delimiter_trim.len())
23525            .collect::<String>();
23526        if delimiter_line.starts_with(delimiter_trim) {
23527            num_of_whitespaces + delimiter_trim.len() <= column as usize
23528        } else {
23529            false
23530        }
23531    };
23532
23533    let mut needs_extra_line = false;
23534    let mut extra_line_additional_indent = IndentSize::spaces(0);
23535
23536    let cursor_is_before_end_tag_if_exists = {
23537        let mut char_position = 0u32;
23538        let mut end_tag_offset = None;
23539
23540        'outer: for chunk in snapshot.text_for_range(range) {
23541            if let Some(byte_pos) = chunk.find(&**end_tag) {
23542                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
23543                end_tag_offset = Some(char_position + chars_before_match);
23544                break 'outer;
23545            }
23546            char_position += chunk.chars().count() as u32;
23547        }
23548
23549        if let Some(end_tag_offset) = end_tag_offset {
23550            let cursor_is_before_end_tag = column <= end_tag_offset;
23551            if cursor_is_after_start_tag {
23552                if cursor_is_before_end_tag {
23553                    needs_extra_line = true;
23554                }
23555                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
23556                if cursor_is_at_start_of_end_tag {
23557                    extra_line_additional_indent.len = *len;
23558                }
23559            }
23560            cursor_is_before_end_tag
23561        } else {
23562            true
23563        }
23564    };
23565
23566    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
23567        && cursor_is_before_end_tag_if_exists
23568    {
23569        let additional_indent = if cursor_is_after_start_tag {
23570            IndentSize::spaces(*len)
23571        } else {
23572            IndentSize::spaces(0)
23573        };
23574
23575        *newline_config = NewlineConfig::Newline {
23576            additional_indent,
23577            extra_line_additional_indent: if needs_extra_line {
23578                Some(extra_line_additional_indent)
23579            } else {
23580                None
23581            },
23582            prevent_auto_indent: true,
23583        };
23584        Some(delimiter.clone())
23585    } else {
23586        None
23587    }
23588}
23589
23590const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
23591
23592fn list_delimiter_for_newline(
23593    start_point: &Point,
23594    buffer: &MultiBufferSnapshot,
23595    language: &LanguageScope,
23596    newline_config: &mut NewlineConfig,
23597) -> Option<Arc<str>> {
23598    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23599
23600    let num_of_whitespaces = snapshot
23601        .chars_for_range(range.clone())
23602        .take_while(|c| c.is_whitespace())
23603        .count();
23604
23605    let task_list_entries: Vec<_> = language
23606        .task_list()
23607        .into_iter()
23608        .flat_map(|config| {
23609            config
23610                .prefixes
23611                .iter()
23612                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
23613        })
23614        .collect();
23615    let unordered_list_entries: Vec<_> = language
23616        .unordered_list()
23617        .iter()
23618        .map(|marker| (marker.as_ref(), marker.as_ref()))
23619        .collect();
23620
23621    let all_entries: Vec<_> = task_list_entries
23622        .into_iter()
23623        .chain(unordered_list_entries)
23624        .collect();
23625
23626    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
23627        let candidate: String = snapshot
23628            .chars_for_range(range.clone())
23629            .skip(num_of_whitespaces)
23630            .take(max_prefix_len)
23631            .collect();
23632
23633        if let Some((prefix, continuation)) = all_entries
23634            .iter()
23635            .filter(|(prefix, _)| candidate.starts_with(*prefix))
23636            .max_by_key(|(prefix, _)| prefix.len())
23637        {
23638            let end_of_prefix = num_of_whitespaces + prefix.len();
23639            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
23640            let has_content_after_marker = snapshot
23641                .chars_for_range(range)
23642                .skip(end_of_prefix)
23643                .any(|c| !c.is_whitespace());
23644
23645            if has_content_after_marker && cursor_is_after_prefix {
23646                return Some((*continuation).into());
23647            }
23648
23649            if start_point.column as usize == end_of_prefix {
23650                if num_of_whitespaces == 0 {
23651                    *newline_config = NewlineConfig::ClearCurrentLine;
23652                } else {
23653                    *newline_config = NewlineConfig::UnindentCurrentLine {
23654                        continuation: (*continuation).into(),
23655                    };
23656                }
23657            }
23658
23659            return None;
23660        }
23661    }
23662
23663    let candidate: String = snapshot
23664        .chars_for_range(range.clone())
23665        .skip(num_of_whitespaces)
23666        .take(ORDERED_LIST_MAX_MARKER_LEN)
23667        .collect();
23668
23669    for ordered_config in language.ordered_list() {
23670        let regex = match Regex::new(&ordered_config.pattern) {
23671            Ok(r) => r,
23672            Err(_) => continue,
23673        };
23674
23675        if let Some(captures) = regex.captures(&candidate) {
23676            let full_match = captures.get(0)?;
23677            let marker_len = full_match.len();
23678            let end_of_prefix = num_of_whitespaces + marker_len;
23679            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
23680
23681            let has_content_after_marker = snapshot
23682                .chars_for_range(range)
23683                .skip(end_of_prefix)
23684                .any(|c| !c.is_whitespace());
23685
23686            if has_content_after_marker && cursor_is_after_prefix {
23687                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
23688                let continuation = ordered_config
23689                    .format
23690                    .replace("{1}", &(number + 1).to_string());
23691                return Some(continuation.into());
23692            }
23693
23694            if start_point.column as usize == end_of_prefix {
23695                let continuation = ordered_config.format.replace("{1}", "1");
23696                if num_of_whitespaces == 0 {
23697                    *newline_config = NewlineConfig::ClearCurrentLine;
23698                } else {
23699                    *newline_config = NewlineConfig::UnindentCurrentLine {
23700                        continuation: continuation.into(),
23701                    };
23702                }
23703            }
23704
23705            return None;
23706        }
23707    }
23708
23709    None
23710}
23711
23712fn is_list_prefix_row(
23713    row: MultiBufferRow,
23714    buffer: &MultiBufferSnapshot,
23715    language: &LanguageScope,
23716) -> bool {
23717    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
23718        return false;
23719    };
23720
23721    let num_of_whitespaces = snapshot
23722        .chars_for_range(range.clone())
23723        .take_while(|c| c.is_whitespace())
23724        .count();
23725
23726    let task_list_prefixes: Vec<_> = language
23727        .task_list()
23728        .into_iter()
23729        .flat_map(|config| {
23730            config
23731                .prefixes
23732                .iter()
23733                .map(|p| p.as_ref())
23734                .collect::<Vec<_>>()
23735        })
23736        .collect();
23737    let unordered_list_markers: Vec<_> = language
23738        .unordered_list()
23739        .iter()
23740        .map(|marker| marker.as_ref())
23741        .collect();
23742    let all_prefixes: Vec<_> = task_list_prefixes
23743        .into_iter()
23744        .chain(unordered_list_markers)
23745        .collect();
23746    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
23747        let candidate: String = snapshot
23748            .chars_for_range(range.clone())
23749            .skip(num_of_whitespaces)
23750            .take(max_prefix_len)
23751            .collect();
23752        if all_prefixes
23753            .iter()
23754            .any(|prefix| candidate.starts_with(*prefix))
23755        {
23756            return true;
23757        }
23758    }
23759
23760    let ordered_list_candidate: String = snapshot
23761        .chars_for_range(range)
23762        .skip(num_of_whitespaces)
23763        .take(ORDERED_LIST_MAX_MARKER_LEN)
23764        .collect();
23765    for ordered_config in language.ordered_list() {
23766        let regex = match Regex::new(&ordered_config.pattern) {
23767            Ok(r) => r,
23768            Err(_) => continue,
23769        };
23770        if let Some(captures) = regex.captures(&ordered_list_candidate) {
23771            return captures.get(0).is_some();
23772        }
23773    }
23774
23775    false
23776}
23777
23778#[derive(Debug)]
23779enum NewlineConfig {
23780    /// Insert newline with optional additional indent and optional extra blank line
23781    Newline {
23782        additional_indent: IndentSize,
23783        extra_line_additional_indent: Option<IndentSize>,
23784        prevent_auto_indent: bool,
23785    },
23786    /// Clear the current line
23787    ClearCurrentLine,
23788    /// Unindent the current line and add continuation
23789    UnindentCurrentLine { continuation: Arc<str> },
23790}
23791
23792impl NewlineConfig {
23793    fn has_extra_line(&self) -> bool {
23794        matches!(
23795            self,
23796            Self::Newline {
23797                extra_line_additional_indent: Some(_),
23798                ..
23799            }
23800        )
23801    }
23802
23803    fn insert_extra_newline_brackets(
23804        buffer: &MultiBufferSnapshot,
23805        range: Range<MultiBufferOffset>,
23806        language: &language::LanguageScope,
23807    ) -> bool {
23808        let leading_whitespace_len = buffer
23809            .reversed_chars_at(range.start)
23810            .take_while(|c| c.is_whitespace() && *c != '\n')
23811            .map(|c| c.len_utf8())
23812            .sum::<usize>();
23813        let trailing_whitespace_len = buffer
23814            .chars_at(range.end)
23815            .take_while(|c| c.is_whitespace() && *c != '\n')
23816            .map(|c| c.len_utf8())
23817            .sum::<usize>();
23818        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23819
23820        language.brackets().any(|(pair, enabled)| {
23821            let pair_start = pair.start.trim_end();
23822            let pair_end = pair.end.trim_start();
23823
23824            enabled
23825                && pair.newline
23826                && buffer.contains_str_at(range.end, pair_end)
23827                && buffer.contains_str_at(
23828                    range.start.saturating_sub_usize(pair_start.len()),
23829                    pair_start,
23830                )
23831        })
23832    }
23833
23834    fn insert_extra_newline_tree_sitter(
23835        buffer: &MultiBufferSnapshot,
23836        range: Range<MultiBufferOffset>,
23837    ) -> bool {
23838        let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23839            [(buffer, range, _)] => (*buffer, range.clone()),
23840            _ => return false,
23841        };
23842        let pair = {
23843            let mut result: Option<BracketMatch<usize>> = None;
23844
23845            for pair in buffer
23846                .all_bracket_ranges(range.start.0..range.end.0)
23847                .filter(move |pair| {
23848                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23849                })
23850            {
23851                let len = pair.close_range.end - pair.open_range.start;
23852
23853                if let Some(existing) = &result {
23854                    let existing_len = existing.close_range.end - existing.open_range.start;
23855                    if len > existing_len {
23856                        continue;
23857                    }
23858                }
23859
23860                result = Some(pair);
23861            }
23862
23863            result
23864        };
23865        let Some(pair) = pair else {
23866            return false;
23867        };
23868        pair.newline_only
23869            && buffer
23870                .chars_for_range(pair.open_range.end..range.start.0)
23871                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23872                .all(|c| c.is_whitespace() && c != '\n')
23873    }
23874}
23875
23876fn update_uncommitted_diff_for_buffer(
23877    editor: Entity<Editor>,
23878    project: &Entity<Project>,
23879    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23880    buffer: Entity<MultiBuffer>,
23881    cx: &mut App,
23882) -> Task<()> {
23883    let mut tasks = Vec::new();
23884    project.update(cx, |project, cx| {
23885        for buffer in buffers {
23886            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23887                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23888            }
23889        }
23890    });
23891    cx.spawn(async move |cx| {
23892        let diffs = future::join_all(tasks).await;
23893        if editor
23894            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23895            .unwrap_or(false)
23896        {
23897            return;
23898        }
23899
23900        buffer
23901            .update(cx, |buffer, cx| {
23902                for diff in diffs.into_iter().flatten() {
23903                    buffer.add_diff(diff, cx);
23904                }
23905            })
23906            .ok();
23907    })
23908}
23909
23910fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23911    let tab_size = tab_size.get() as usize;
23912    let mut width = offset;
23913
23914    for ch in text.chars() {
23915        width += if ch == '\t' {
23916            tab_size - (width % tab_size)
23917        } else {
23918            1
23919        };
23920    }
23921
23922    width - offset
23923}
23924
23925#[cfg(test)]
23926mod tests {
23927    use super::*;
23928
23929    #[test]
23930    fn test_string_size_with_expanded_tabs() {
23931        let nz = |val| NonZeroU32::new(val).unwrap();
23932        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23933        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23934        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23935        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23936        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23937        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23938        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23939        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23940    }
23941}
23942
23943/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23944struct WordBreakingTokenizer<'a> {
23945    input: &'a str,
23946}
23947
23948impl<'a> WordBreakingTokenizer<'a> {
23949    fn new(input: &'a str) -> Self {
23950        Self { input }
23951    }
23952}
23953
23954fn is_char_ideographic(ch: char) -> bool {
23955    use unicode_script::Script::*;
23956    use unicode_script::UnicodeScript;
23957    matches!(ch.script(), Han | Tangut | Yi)
23958}
23959
23960fn is_grapheme_ideographic(text: &str) -> bool {
23961    text.chars().any(is_char_ideographic)
23962}
23963
23964fn is_grapheme_whitespace(text: &str) -> bool {
23965    text.chars().any(|x| x.is_whitespace())
23966}
23967
23968fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23969    text.chars()
23970        .next()
23971        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23972}
23973
23974#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23975enum WordBreakToken<'a> {
23976    Word { token: &'a str, grapheme_len: usize },
23977    InlineWhitespace { token: &'a str, grapheme_len: usize },
23978    Newline,
23979}
23980
23981impl<'a> Iterator for WordBreakingTokenizer<'a> {
23982    /// Yields a span, the count of graphemes in the token, and whether it was
23983    /// whitespace. Note that it also breaks at word boundaries.
23984    type Item = WordBreakToken<'a>;
23985
23986    fn next(&mut self) -> Option<Self::Item> {
23987        use unicode_segmentation::UnicodeSegmentation;
23988        if self.input.is_empty() {
23989            return None;
23990        }
23991
23992        let mut iter = self.input.graphemes(true).peekable();
23993        let mut offset = 0;
23994        let mut grapheme_len = 0;
23995        if let Some(first_grapheme) = iter.next() {
23996            let is_newline = first_grapheme == "\n";
23997            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23998            offset += first_grapheme.len();
23999            grapheme_len += 1;
24000            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
24001                if let Some(grapheme) = iter.peek().copied()
24002                    && should_stay_with_preceding_ideograph(grapheme)
24003                {
24004                    offset += grapheme.len();
24005                    grapheme_len += 1;
24006                }
24007            } else {
24008                let mut words = self.input[offset..].split_word_bound_indices().peekable();
24009                let mut next_word_bound = words.peek().copied();
24010                if next_word_bound.is_some_and(|(i, _)| i == 0) {
24011                    next_word_bound = words.next();
24012                }
24013                while let Some(grapheme) = iter.peek().copied() {
24014                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
24015                        break;
24016                    };
24017                    if is_grapheme_whitespace(grapheme) != is_whitespace
24018                        || (grapheme == "\n") != is_newline
24019                    {
24020                        break;
24021                    };
24022                    offset += grapheme.len();
24023                    grapheme_len += 1;
24024                    iter.next();
24025                }
24026            }
24027            let token = &self.input[..offset];
24028            self.input = &self.input[offset..];
24029            if token == "\n" {
24030                Some(WordBreakToken::Newline)
24031            } else if is_whitespace {
24032                Some(WordBreakToken::InlineWhitespace {
24033                    token,
24034                    grapheme_len,
24035                })
24036            } else {
24037                Some(WordBreakToken::Word {
24038                    token,
24039                    grapheme_len,
24040                })
24041            }
24042        } else {
24043            None
24044        }
24045    }
24046}
24047
24048#[test]
24049fn test_word_breaking_tokenizer() {
24050    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
24051        ("", &[]),
24052        ("  ", &[whitespace("  ", 2)]),
24053        ("Ʒ", &[word("Ʒ", 1)]),
24054        ("Ǽ", &[word("Ǽ", 1)]),
24055        ("", &[word("", 1)]),
24056        ("⋑⋑", &[word("⋑⋑", 2)]),
24057        (
24058            "原理,进而",
24059            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
24060        ),
24061        (
24062            "hello world",
24063            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
24064        ),
24065        (
24066            "hello, world",
24067            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
24068        ),
24069        (
24070            "  hello world",
24071            &[
24072                whitespace("  ", 2),
24073                word("hello", 5),
24074                whitespace(" ", 1),
24075                word("world", 5),
24076            ],
24077        ),
24078        (
24079            "这是什么 \n 钢笔",
24080            &[
24081                word("", 1),
24082                word("", 1),
24083                word("", 1),
24084                word("", 1),
24085                whitespace(" ", 1),
24086                newline(),
24087                whitespace(" ", 1),
24088                word("", 1),
24089                word("", 1),
24090            ],
24091        ),
24092        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
24093    ];
24094
24095    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24096        WordBreakToken::Word {
24097            token,
24098            grapheme_len,
24099        }
24100    }
24101
24102    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24103        WordBreakToken::InlineWhitespace {
24104            token,
24105            grapheme_len,
24106        }
24107    }
24108
24109    fn newline() -> WordBreakToken<'static> {
24110        WordBreakToken::Newline
24111    }
24112
24113    for (input, result) in tests {
24114        assert_eq!(
24115            WordBreakingTokenizer::new(input)
24116                .collect::<Vec<_>>()
24117                .as_slice(),
24118            *result,
24119        );
24120    }
24121}
24122
24123fn wrap_with_prefix(
24124    first_line_prefix: String,
24125    subsequent_lines_prefix: String,
24126    unwrapped_text: String,
24127    wrap_column: usize,
24128    tab_size: NonZeroU32,
24129    preserve_existing_whitespace: bool,
24130) -> String {
24131    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
24132    let subsequent_lines_prefix_len =
24133        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
24134    let mut wrapped_text = String::new();
24135    let mut current_line = first_line_prefix;
24136    let mut is_first_line = true;
24137
24138    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
24139    let mut current_line_len = first_line_prefix_len;
24140    let mut in_whitespace = false;
24141    for token in tokenizer {
24142        let have_preceding_whitespace = in_whitespace;
24143        match token {
24144            WordBreakToken::Word {
24145                token,
24146                grapheme_len,
24147            } => {
24148                in_whitespace = false;
24149                let current_prefix_len = if is_first_line {
24150                    first_line_prefix_len
24151                } else {
24152                    subsequent_lines_prefix_len
24153                };
24154                if current_line_len + grapheme_len > wrap_column
24155                    && current_line_len != current_prefix_len
24156                {
24157                    wrapped_text.push_str(current_line.trim_end());
24158                    wrapped_text.push('\n');
24159                    is_first_line = false;
24160                    current_line = subsequent_lines_prefix.clone();
24161                    current_line_len = subsequent_lines_prefix_len;
24162                }
24163                current_line.push_str(token);
24164                current_line_len += grapheme_len;
24165            }
24166            WordBreakToken::InlineWhitespace {
24167                mut token,
24168                mut grapheme_len,
24169            } => {
24170                in_whitespace = true;
24171                if have_preceding_whitespace && !preserve_existing_whitespace {
24172                    continue;
24173                }
24174                if !preserve_existing_whitespace {
24175                    // Keep a single whitespace grapheme as-is
24176                    if let Some(first) =
24177                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
24178                    {
24179                        token = first;
24180                    } else {
24181                        token = " ";
24182                    }
24183                    grapheme_len = 1;
24184                }
24185                let current_prefix_len = if is_first_line {
24186                    first_line_prefix_len
24187                } else {
24188                    subsequent_lines_prefix_len
24189                };
24190                if current_line_len + grapheme_len > wrap_column {
24191                    wrapped_text.push_str(current_line.trim_end());
24192                    wrapped_text.push('\n');
24193                    is_first_line = false;
24194                    current_line = subsequent_lines_prefix.clone();
24195                    current_line_len = subsequent_lines_prefix_len;
24196                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
24197                    current_line.push_str(token);
24198                    current_line_len += grapheme_len;
24199                }
24200            }
24201            WordBreakToken::Newline => {
24202                in_whitespace = true;
24203                let current_prefix_len = if is_first_line {
24204                    first_line_prefix_len
24205                } else {
24206                    subsequent_lines_prefix_len
24207                };
24208                if preserve_existing_whitespace {
24209                    wrapped_text.push_str(current_line.trim_end());
24210                    wrapped_text.push('\n');
24211                    is_first_line = false;
24212                    current_line = subsequent_lines_prefix.clone();
24213                    current_line_len = subsequent_lines_prefix_len;
24214                } else if have_preceding_whitespace {
24215                    continue;
24216                } else if current_line_len + 1 > wrap_column
24217                    && current_line_len != current_prefix_len
24218                {
24219                    wrapped_text.push_str(current_line.trim_end());
24220                    wrapped_text.push('\n');
24221                    is_first_line = false;
24222                    current_line = subsequent_lines_prefix.clone();
24223                    current_line_len = subsequent_lines_prefix_len;
24224                } else if current_line_len != current_prefix_len {
24225                    current_line.push(' ');
24226                    current_line_len += 1;
24227                }
24228            }
24229        }
24230    }
24231
24232    if !current_line.is_empty() {
24233        wrapped_text.push_str(&current_line);
24234    }
24235    wrapped_text
24236}
24237
24238#[test]
24239fn test_wrap_with_prefix() {
24240    assert_eq!(
24241        wrap_with_prefix(
24242            "# ".to_string(),
24243            "# ".to_string(),
24244            "abcdefg".to_string(),
24245            4,
24246            NonZeroU32::new(4).unwrap(),
24247            false,
24248        ),
24249        "# abcdefg"
24250    );
24251    assert_eq!(
24252        wrap_with_prefix(
24253            "".to_string(),
24254            "".to_string(),
24255            "\thello world".to_string(),
24256            8,
24257            NonZeroU32::new(4).unwrap(),
24258            false,
24259        ),
24260        "hello\nworld"
24261    );
24262    assert_eq!(
24263        wrap_with_prefix(
24264            "// ".to_string(),
24265            "// ".to_string(),
24266            "xx \nyy zz aa bb cc".to_string(),
24267            12,
24268            NonZeroU32::new(4).unwrap(),
24269            false,
24270        ),
24271        "// xx yy zz\n// aa bb cc"
24272    );
24273    assert_eq!(
24274        wrap_with_prefix(
24275            String::new(),
24276            String::new(),
24277            "这是什么 \n 钢笔".to_string(),
24278            3,
24279            NonZeroU32::new(4).unwrap(),
24280            false,
24281        ),
24282        "这是什\n么 钢\n"
24283    );
24284    assert_eq!(
24285        wrap_with_prefix(
24286            String::new(),
24287            String::new(),
24288            format!("foo{}bar", '\u{2009}'), // thin space
24289            80,
24290            NonZeroU32::new(4).unwrap(),
24291            false,
24292        ),
24293        format!("foo{}bar", '\u{2009}')
24294    );
24295}
24296
24297pub trait CollaborationHub {
24298    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
24299    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
24300    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
24301}
24302
24303impl CollaborationHub for Entity<Project> {
24304    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
24305        self.read(cx).collaborators()
24306    }
24307
24308    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
24309        self.read(cx).user_store().read(cx).participant_indices()
24310    }
24311
24312    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
24313        let this = self.read(cx);
24314        let user_ids = this.collaborators().values().map(|c| c.user_id);
24315        this.user_store().read(cx).participant_names(user_ids, cx)
24316    }
24317}
24318
24319pub trait SemanticsProvider {
24320    fn hover(
24321        &self,
24322        buffer: &Entity<Buffer>,
24323        position: text::Anchor,
24324        cx: &mut App,
24325    ) -> Option<Task<Option<Vec<project::Hover>>>>;
24326
24327    fn inline_values(
24328        &self,
24329        buffer_handle: Entity<Buffer>,
24330        range: Range<text::Anchor>,
24331        cx: &mut App,
24332    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
24333
24334    fn applicable_inlay_chunks(
24335        &self,
24336        buffer: &Entity<Buffer>,
24337        ranges: &[Range<text::Anchor>],
24338        cx: &mut App,
24339    ) -> Vec<Range<BufferRow>>;
24340
24341    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
24342
24343    fn inlay_hints(
24344        &self,
24345        invalidate: InvalidationStrategy,
24346        buffer: Entity<Buffer>,
24347        ranges: Vec<Range<text::Anchor>>,
24348        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24349        cx: &mut App,
24350    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
24351
24352    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
24353
24354    fn document_highlights(
24355        &self,
24356        buffer: &Entity<Buffer>,
24357        position: text::Anchor,
24358        cx: &mut App,
24359    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
24360
24361    fn definitions(
24362        &self,
24363        buffer: &Entity<Buffer>,
24364        position: text::Anchor,
24365        kind: GotoDefinitionKind,
24366        cx: &mut App,
24367    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
24368
24369    fn range_for_rename(
24370        &self,
24371        buffer: &Entity<Buffer>,
24372        position: text::Anchor,
24373        cx: &mut App,
24374    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
24375
24376    fn perform_rename(
24377        &self,
24378        buffer: &Entity<Buffer>,
24379        position: text::Anchor,
24380        new_name: String,
24381        cx: &mut App,
24382    ) -> Option<Task<Result<ProjectTransaction>>>;
24383}
24384
24385pub trait CompletionProvider {
24386    fn completions(
24387        &self,
24388        excerpt_id: ExcerptId,
24389        buffer: &Entity<Buffer>,
24390        buffer_position: text::Anchor,
24391        trigger: CompletionContext,
24392        window: &mut Window,
24393        cx: &mut Context<Editor>,
24394    ) -> Task<Result<Vec<CompletionResponse>>>;
24395
24396    fn resolve_completions(
24397        &self,
24398        _buffer: Entity<Buffer>,
24399        _completion_indices: Vec<usize>,
24400        _completions: Rc<RefCell<Box<[Completion]>>>,
24401        _cx: &mut Context<Editor>,
24402    ) -> Task<Result<bool>> {
24403        Task::ready(Ok(false))
24404    }
24405
24406    fn apply_additional_edits_for_completion(
24407        &self,
24408        _buffer: Entity<Buffer>,
24409        _completions: Rc<RefCell<Box<[Completion]>>>,
24410        _completion_index: usize,
24411        _push_to_history: bool,
24412        _cx: &mut Context<Editor>,
24413    ) -> Task<Result<Option<language::Transaction>>> {
24414        Task::ready(Ok(None))
24415    }
24416
24417    fn is_completion_trigger(
24418        &self,
24419        buffer: &Entity<Buffer>,
24420        position: language::Anchor,
24421        text: &str,
24422        trigger_in_words: bool,
24423        cx: &mut Context<Editor>,
24424    ) -> bool;
24425
24426    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24427
24428    fn sort_completions(&self) -> bool {
24429        true
24430    }
24431
24432    fn filter_completions(&self) -> bool {
24433        true
24434    }
24435
24436    fn show_snippets(&self) -> bool {
24437        false
24438    }
24439}
24440
24441pub trait CodeActionProvider {
24442    fn id(&self) -> Arc<str>;
24443
24444    fn code_actions(
24445        &self,
24446        buffer: &Entity<Buffer>,
24447        range: Range<text::Anchor>,
24448        window: &mut Window,
24449        cx: &mut App,
24450    ) -> Task<Result<Vec<CodeAction>>>;
24451
24452    fn apply_code_action(
24453        &self,
24454        buffer_handle: Entity<Buffer>,
24455        action: CodeAction,
24456        excerpt_id: ExcerptId,
24457        push_to_history: bool,
24458        window: &mut Window,
24459        cx: &mut App,
24460    ) -> Task<Result<ProjectTransaction>>;
24461}
24462
24463impl CodeActionProvider for Entity<Project> {
24464    fn id(&self) -> Arc<str> {
24465        "project".into()
24466    }
24467
24468    fn code_actions(
24469        &self,
24470        buffer: &Entity<Buffer>,
24471        range: Range<text::Anchor>,
24472        _window: &mut Window,
24473        cx: &mut App,
24474    ) -> Task<Result<Vec<CodeAction>>> {
24475        self.update(cx, |project, cx| {
24476            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24477            let code_actions = project.code_actions(buffer, range, None, cx);
24478            cx.background_spawn(async move {
24479                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24480                Ok(code_lens_actions
24481                    .context("code lens fetch")?
24482                    .into_iter()
24483                    .flatten()
24484                    .chain(
24485                        code_actions
24486                            .context("code action fetch")?
24487                            .into_iter()
24488                            .flatten(),
24489                    )
24490                    .collect())
24491            })
24492        })
24493    }
24494
24495    fn apply_code_action(
24496        &self,
24497        buffer_handle: Entity<Buffer>,
24498        action: CodeAction,
24499        _excerpt_id: ExcerptId,
24500        push_to_history: bool,
24501        _window: &mut Window,
24502        cx: &mut App,
24503    ) -> Task<Result<ProjectTransaction>> {
24504        self.update(cx, |project, cx| {
24505            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24506        })
24507    }
24508}
24509
24510fn snippet_completions(
24511    project: &Project,
24512    buffer: &Entity<Buffer>,
24513    buffer_anchor: text::Anchor,
24514    classifier: CharClassifier,
24515    cx: &mut App,
24516) -> Task<Result<CompletionResponse>> {
24517    let languages = buffer.read(cx).languages_at(buffer_anchor);
24518    let snippet_store = project.snippets().read(cx);
24519
24520    let scopes: Vec<_> = languages
24521        .iter()
24522        .filter_map(|language| {
24523            let language_name = language.lsp_id();
24524            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24525
24526            if snippets.is_empty() {
24527                None
24528            } else {
24529                Some((language.default_scope(), snippets))
24530            }
24531        })
24532        .collect();
24533
24534    if scopes.is_empty() {
24535        return Task::ready(Ok(CompletionResponse {
24536            completions: vec![],
24537            display_options: CompletionDisplayOptions::default(),
24538            is_incomplete: false,
24539        }));
24540    }
24541
24542    let snapshot = buffer.read(cx).text_snapshot();
24543    let executor = cx.background_executor().clone();
24544
24545    cx.background_spawn(async move {
24546        let is_word_char = |c| classifier.is_word(c);
24547
24548        let mut is_incomplete = false;
24549        let mut completions: Vec<Completion> = Vec::new();
24550
24551        const MAX_PREFIX_LEN: usize = 128;
24552        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24553        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24554        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24555
24556        let max_buffer_window: String = snapshot
24557            .text_for_range(window_start..buffer_offset)
24558            .collect();
24559
24560        if max_buffer_window.is_empty() {
24561            return Ok(CompletionResponse {
24562                completions: vec![],
24563                display_options: CompletionDisplayOptions::default(),
24564                is_incomplete: true,
24565            });
24566        }
24567
24568        for (_scope, snippets) in scopes.into_iter() {
24569            // Sort snippets by word count to match longer snippet prefixes first.
24570            let mut sorted_snippet_candidates = snippets
24571                .iter()
24572                .enumerate()
24573                .flat_map(|(snippet_ix, snippet)| {
24574                    snippet
24575                        .prefix
24576                        .iter()
24577                        .enumerate()
24578                        .map(move |(prefix_ix, prefix)| {
24579                            let word_count =
24580                                snippet_candidate_suffixes(prefix, is_word_char).count();
24581                            ((snippet_ix, prefix_ix), prefix, word_count)
24582                        })
24583                })
24584                .collect_vec();
24585            sorted_snippet_candidates
24586                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24587
24588            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24589
24590            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24591                .take(
24592                    sorted_snippet_candidates
24593                        .first()
24594                        .map(|(_, _, word_count)| *word_count)
24595                        .unwrap_or_default(),
24596                )
24597                .collect_vec();
24598
24599            const MAX_RESULTS: usize = 100;
24600            // Each match also remembers how many characters from the buffer it consumed
24601            let mut matches: Vec<(StringMatch, usize)> = vec![];
24602
24603            let mut snippet_list_cutoff_index = 0;
24604            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24605                let word_count = buffer_index + 1;
24606                // Increase `snippet_list_cutoff_index` until we have all of the
24607                // snippets with sufficiently many words.
24608                while sorted_snippet_candidates
24609                    .get(snippet_list_cutoff_index)
24610                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24611                        *snippet_word_count >= word_count
24612                    })
24613                {
24614                    snippet_list_cutoff_index += 1;
24615                }
24616
24617                // Take only the candidates with at least `word_count` many words
24618                let snippet_candidates_at_word_len =
24619                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24620
24621                let candidates = snippet_candidates_at_word_len
24622                    .iter()
24623                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24624                    .enumerate() // index in `sorted_snippet_candidates`
24625                    // First char must match
24626                    .filter(|(_ix, prefix)| {
24627                        itertools::equal(
24628                            prefix
24629                                .chars()
24630                                .next()
24631                                .into_iter()
24632                                .flat_map(|c| c.to_lowercase()),
24633                            buffer_window
24634                                .chars()
24635                                .next()
24636                                .into_iter()
24637                                .flat_map(|c| c.to_lowercase()),
24638                        )
24639                    })
24640                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24641                    .collect::<Vec<StringMatchCandidate>>();
24642
24643                matches.extend(
24644                    fuzzy::match_strings(
24645                        &candidates,
24646                        &buffer_window,
24647                        buffer_window.chars().any(|c| c.is_uppercase()),
24648                        true,
24649                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24650                        &Default::default(),
24651                        executor.clone(),
24652                    )
24653                    .await
24654                    .into_iter()
24655                    .map(|string_match| (string_match, buffer_window.len())),
24656                );
24657
24658                if matches.len() >= MAX_RESULTS {
24659                    break;
24660                }
24661            }
24662
24663            let to_lsp = |point: &text::Anchor| {
24664                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24665                point_to_lsp(end)
24666            };
24667            let lsp_end = to_lsp(&buffer_anchor);
24668
24669            if matches.len() >= MAX_RESULTS {
24670                is_incomplete = true;
24671            }
24672
24673            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24674                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24675                    sorted_snippet_candidates[string_match.candidate_id];
24676                let snippet = &snippets[snippet_index];
24677                let start = buffer_offset - buffer_window_len;
24678                let start = snapshot.anchor_before(start);
24679                let range = start..buffer_anchor;
24680                let lsp_start = to_lsp(&start);
24681                let lsp_range = lsp::Range {
24682                    start: lsp_start,
24683                    end: lsp_end,
24684                };
24685                Completion {
24686                    replace_range: range,
24687                    new_text: snippet.body.clone(),
24688                    source: CompletionSource::Lsp {
24689                        insert_range: None,
24690                        server_id: LanguageServerId(usize::MAX),
24691                        resolved: true,
24692                        lsp_completion: Box::new(lsp::CompletionItem {
24693                            label: snippet.prefix.first().unwrap().clone(),
24694                            kind: Some(CompletionItemKind::SNIPPET),
24695                            label_details: snippet.description.as_ref().map(|description| {
24696                                lsp::CompletionItemLabelDetails {
24697                                    detail: Some(description.clone()),
24698                                    description: None,
24699                                }
24700                            }),
24701                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24702                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24703                                lsp::InsertReplaceEdit {
24704                                    new_text: snippet.body.clone(),
24705                                    insert: lsp_range,
24706                                    replace: lsp_range,
24707                                },
24708                            )),
24709                            filter_text: Some(snippet.body.clone()),
24710                            sort_text: Some(char::MAX.to_string()),
24711                            ..lsp::CompletionItem::default()
24712                        }),
24713                        lsp_defaults: None,
24714                    },
24715                    label: CodeLabel {
24716                        text: matching_prefix.clone(),
24717                        runs: Vec::new(),
24718                        filter_range: 0..matching_prefix.len(),
24719                    },
24720                    icon_path: None,
24721                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24722                        single_line: snippet.name.clone().into(),
24723                        plain_text: snippet
24724                            .description
24725                            .clone()
24726                            .map(|description| description.into()),
24727                    }),
24728                    insert_text_mode: None,
24729                    confirm: None,
24730                    match_start: Some(start),
24731                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24732                }
24733            }));
24734        }
24735
24736        Ok(CompletionResponse {
24737            completions,
24738            display_options: CompletionDisplayOptions::default(),
24739            is_incomplete,
24740        })
24741    })
24742}
24743
24744impl CompletionProvider for Entity<Project> {
24745    fn completions(
24746        &self,
24747        _excerpt_id: ExcerptId,
24748        buffer: &Entity<Buffer>,
24749        buffer_position: text::Anchor,
24750        options: CompletionContext,
24751        _window: &mut Window,
24752        cx: &mut Context<Editor>,
24753    ) -> Task<Result<Vec<CompletionResponse>>> {
24754        self.update(cx, |project, cx| {
24755            let task = project.completions(buffer, buffer_position, options, cx);
24756            cx.background_spawn(task)
24757        })
24758    }
24759
24760    fn resolve_completions(
24761        &self,
24762        buffer: Entity<Buffer>,
24763        completion_indices: Vec<usize>,
24764        completions: Rc<RefCell<Box<[Completion]>>>,
24765        cx: &mut Context<Editor>,
24766    ) -> Task<Result<bool>> {
24767        self.update(cx, |project, cx| {
24768            project.lsp_store().update(cx, |lsp_store, cx| {
24769                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24770            })
24771        })
24772    }
24773
24774    fn apply_additional_edits_for_completion(
24775        &self,
24776        buffer: Entity<Buffer>,
24777        completions: Rc<RefCell<Box<[Completion]>>>,
24778        completion_index: usize,
24779        push_to_history: bool,
24780        cx: &mut Context<Editor>,
24781    ) -> Task<Result<Option<language::Transaction>>> {
24782        self.update(cx, |project, cx| {
24783            project.lsp_store().update(cx, |lsp_store, cx| {
24784                lsp_store.apply_additional_edits_for_completion(
24785                    buffer,
24786                    completions,
24787                    completion_index,
24788                    push_to_history,
24789                    cx,
24790                )
24791            })
24792        })
24793    }
24794
24795    fn is_completion_trigger(
24796        &self,
24797        buffer: &Entity<Buffer>,
24798        position: language::Anchor,
24799        text: &str,
24800        trigger_in_words: bool,
24801        cx: &mut Context<Editor>,
24802    ) -> bool {
24803        let mut chars = text.chars();
24804        let char = if let Some(char) = chars.next() {
24805            char
24806        } else {
24807            return false;
24808        };
24809        if chars.next().is_some() {
24810            return false;
24811        }
24812
24813        let buffer = buffer.read(cx);
24814        let snapshot = buffer.snapshot();
24815        let classifier = snapshot
24816            .char_classifier_at(position)
24817            .scope_context(Some(CharScopeContext::Completion));
24818        if trigger_in_words && classifier.is_word(char) {
24819            return true;
24820        }
24821
24822        buffer.completion_triggers().contains(text)
24823    }
24824
24825    fn show_snippets(&self) -> bool {
24826        true
24827    }
24828}
24829
24830impl SemanticsProvider for Entity<Project> {
24831    fn hover(
24832        &self,
24833        buffer: &Entity<Buffer>,
24834        position: text::Anchor,
24835        cx: &mut App,
24836    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24837        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24838    }
24839
24840    fn document_highlights(
24841        &self,
24842        buffer: &Entity<Buffer>,
24843        position: text::Anchor,
24844        cx: &mut App,
24845    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24846        Some(self.update(cx, |project, cx| {
24847            project.document_highlights(buffer, position, cx)
24848        }))
24849    }
24850
24851    fn definitions(
24852        &self,
24853        buffer: &Entity<Buffer>,
24854        position: text::Anchor,
24855        kind: GotoDefinitionKind,
24856        cx: &mut App,
24857    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24858        Some(self.update(cx, |project, cx| match kind {
24859            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24860            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24861            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24862            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24863        }))
24864    }
24865
24866    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24867        self.update(cx, |project, cx| {
24868            if project
24869                .active_debug_session(cx)
24870                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24871            {
24872                return true;
24873            }
24874
24875            buffer.update(cx, |buffer, cx| {
24876                project.any_language_server_supports_inlay_hints(buffer, cx)
24877            })
24878        })
24879    }
24880
24881    fn inline_values(
24882        &self,
24883        buffer_handle: Entity<Buffer>,
24884        range: Range<text::Anchor>,
24885        cx: &mut App,
24886    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24887        self.update(cx, |project, cx| {
24888            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24889
24890            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24891        })
24892    }
24893
24894    fn applicable_inlay_chunks(
24895        &self,
24896        buffer: &Entity<Buffer>,
24897        ranges: &[Range<text::Anchor>],
24898        cx: &mut App,
24899    ) -> Vec<Range<BufferRow>> {
24900        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24901            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24902        })
24903    }
24904
24905    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24906        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24907            lsp_store.invalidate_inlay_hints(for_buffers)
24908        });
24909    }
24910
24911    fn inlay_hints(
24912        &self,
24913        invalidate: InvalidationStrategy,
24914        buffer: Entity<Buffer>,
24915        ranges: Vec<Range<text::Anchor>>,
24916        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24917        cx: &mut App,
24918    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24919        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24920            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24921        }))
24922    }
24923
24924    fn range_for_rename(
24925        &self,
24926        buffer: &Entity<Buffer>,
24927        position: text::Anchor,
24928        cx: &mut App,
24929    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24930        Some(self.update(cx, |project, cx| {
24931            let buffer = buffer.clone();
24932            let task = project.prepare_rename(buffer.clone(), position, cx);
24933            cx.spawn(async move |_, cx| {
24934                Ok(match task.await? {
24935                    PrepareRenameResponse::Success(range) => Some(range),
24936                    PrepareRenameResponse::InvalidPosition => None,
24937                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24938                        // Fallback on using TreeSitter info to determine identifier range
24939                        buffer.read_with(cx, |buffer, _| {
24940                            let snapshot = buffer.snapshot();
24941                            let (range, kind) = snapshot.surrounding_word(position, None);
24942                            if kind != Some(CharKind::Word) {
24943                                return None;
24944                            }
24945                            Some(
24946                                snapshot.anchor_before(range.start)
24947                                    ..snapshot.anchor_after(range.end),
24948                            )
24949                        })?
24950                    }
24951                })
24952            })
24953        }))
24954    }
24955
24956    fn perform_rename(
24957        &self,
24958        buffer: &Entity<Buffer>,
24959        position: text::Anchor,
24960        new_name: String,
24961        cx: &mut App,
24962    ) -> Option<Task<Result<ProjectTransaction>>> {
24963        Some(self.update(cx, |project, cx| {
24964            project.perform_rename(buffer.clone(), position, new_name, cx)
24965        }))
24966    }
24967}
24968
24969fn consume_contiguous_rows(
24970    contiguous_row_selections: &mut Vec<Selection<Point>>,
24971    selection: &Selection<Point>,
24972    display_map: &DisplaySnapshot,
24973    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24974) -> (MultiBufferRow, MultiBufferRow) {
24975    contiguous_row_selections.push(selection.clone());
24976    let start_row = starting_row(selection, display_map);
24977    let mut end_row = ending_row(selection, display_map);
24978
24979    while let Some(next_selection) = selections.peek() {
24980        if next_selection.start.row <= end_row.0 {
24981            end_row = ending_row(next_selection, display_map);
24982            contiguous_row_selections.push(selections.next().unwrap().clone());
24983        } else {
24984            break;
24985        }
24986    }
24987    (start_row, end_row)
24988}
24989
24990fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24991    if selection.start.column > 0 {
24992        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24993    } else {
24994        MultiBufferRow(selection.start.row)
24995    }
24996}
24997
24998fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24999    if next_selection.end.column > 0 || next_selection.is_empty() {
25000        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
25001    } else {
25002        MultiBufferRow(next_selection.end.row)
25003    }
25004}
25005
25006impl EditorSnapshot {
25007    pub fn remote_selections_in_range<'a>(
25008        &'a self,
25009        range: &'a Range<Anchor>,
25010        collaboration_hub: &dyn CollaborationHub,
25011        cx: &'a App,
25012    ) -> impl 'a + Iterator<Item = RemoteSelection> {
25013        let participant_names = collaboration_hub.user_names(cx);
25014        let participant_indices = collaboration_hub.user_participant_indices(cx);
25015        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
25016        let collaborators_by_replica_id = collaborators_by_peer_id
25017            .values()
25018            .map(|collaborator| (collaborator.replica_id, collaborator))
25019            .collect::<HashMap<_, _>>();
25020        self.buffer_snapshot()
25021            .selections_in_range(range, false)
25022            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
25023                if replica_id == ReplicaId::AGENT {
25024                    Some(RemoteSelection {
25025                        replica_id,
25026                        selection,
25027                        cursor_shape,
25028                        line_mode,
25029                        collaborator_id: CollaboratorId::Agent,
25030                        user_name: Some("Agent".into()),
25031                        color: cx.theme().players().agent(),
25032                    })
25033                } else {
25034                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
25035                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
25036                    let user_name = participant_names.get(&collaborator.user_id).cloned();
25037                    Some(RemoteSelection {
25038                        replica_id,
25039                        selection,
25040                        cursor_shape,
25041                        line_mode,
25042                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
25043                        user_name,
25044                        color: if let Some(index) = participant_index {
25045                            cx.theme().players().color_for_participant(index.0)
25046                        } else {
25047                            cx.theme().players().absent()
25048                        },
25049                    })
25050                }
25051            })
25052    }
25053
25054    pub fn hunks_for_ranges(
25055        &self,
25056        ranges: impl IntoIterator<Item = Range<Point>>,
25057    ) -> Vec<MultiBufferDiffHunk> {
25058        let mut hunks = Vec::new();
25059        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
25060            HashMap::default();
25061        for query_range in ranges {
25062            let query_rows =
25063                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
25064            for hunk in self.buffer_snapshot().diff_hunks_in_range(
25065                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
25066            ) {
25067                // Include deleted hunks that are adjacent to the query range, because
25068                // otherwise they would be missed.
25069                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
25070                if hunk.status().is_deleted() {
25071                    intersects_range |= hunk.row_range.start == query_rows.end;
25072                    intersects_range |= hunk.row_range.end == query_rows.start;
25073                }
25074                if intersects_range {
25075                    if !processed_buffer_rows
25076                        .entry(hunk.buffer_id)
25077                        .or_default()
25078                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
25079                    {
25080                        continue;
25081                    }
25082                    hunks.push(hunk);
25083                }
25084            }
25085        }
25086
25087        hunks
25088    }
25089
25090    fn display_diff_hunks_for_rows<'a>(
25091        &'a self,
25092        display_rows: Range<DisplayRow>,
25093        folded_buffers: &'a HashSet<BufferId>,
25094    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
25095        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
25096        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
25097
25098        self.buffer_snapshot()
25099            .diff_hunks_in_range(buffer_start..buffer_end)
25100            .filter_map(|hunk| {
25101                if folded_buffers.contains(&hunk.buffer_id) {
25102                    return None;
25103                }
25104
25105                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
25106                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
25107
25108                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
25109                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
25110
25111                let display_hunk = if hunk_display_start.column() != 0 {
25112                    DisplayDiffHunk::Folded {
25113                        display_row: hunk_display_start.row(),
25114                    }
25115                } else {
25116                    let mut end_row = hunk_display_end.row();
25117                    if hunk_display_end.column() > 0 {
25118                        end_row.0 += 1;
25119                    }
25120                    let is_created_file = hunk.is_created_file();
25121
25122                    DisplayDiffHunk::Unfolded {
25123                        status: hunk.status(),
25124                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
25125                            ..hunk.diff_base_byte_range.end.0,
25126                        word_diffs: hunk.word_diffs,
25127                        display_row_range: hunk_display_start.row()..end_row,
25128                        multi_buffer_range: Anchor::range_in_buffer(
25129                            hunk.excerpt_id,
25130                            hunk.buffer_range,
25131                        ),
25132                        is_created_file,
25133                    }
25134                };
25135
25136                Some(display_hunk)
25137            })
25138    }
25139
25140    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
25141        self.display_snapshot
25142            .buffer_snapshot()
25143            .language_at(position)
25144    }
25145
25146    pub fn is_focused(&self) -> bool {
25147        self.is_focused
25148    }
25149
25150    pub fn placeholder_text(&self) -> Option<String> {
25151        self.placeholder_display_snapshot
25152            .as_ref()
25153            .map(|display_map| display_map.text())
25154    }
25155
25156    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
25157        self.scroll_anchor.scroll_position(&self.display_snapshot)
25158    }
25159
25160    pub fn gutter_dimensions(
25161        &self,
25162        font_id: FontId,
25163        font_size: Pixels,
25164        style: &EditorStyle,
25165        window: &mut Window,
25166        cx: &App,
25167    ) -> GutterDimensions {
25168        if self.show_gutter
25169            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
25170            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
25171        {
25172            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
25173                matches!(
25174                    ProjectSettings::get_global(cx).git.git_gutter,
25175                    GitGutterSetting::TrackedFiles
25176                )
25177            });
25178            let gutter_settings = EditorSettings::get_global(cx).gutter;
25179            let show_line_numbers = self
25180                .show_line_numbers
25181                .unwrap_or(gutter_settings.line_numbers);
25182            let line_gutter_width = if show_line_numbers {
25183                // Avoid flicker-like gutter resizes when the line number gains another digit by
25184                // only resizing the gutter on files with > 10**min_line_number_digits lines.
25185                let min_width_for_number_on_gutter =
25186                    ch_advance * gutter_settings.min_line_number_digits as f32;
25187                self.max_line_number_width(style, window)
25188                    .max(min_width_for_number_on_gutter)
25189            } else {
25190                0.0.into()
25191            };
25192
25193            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
25194            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
25195
25196            let git_blame_entries_width =
25197                self.git_blame_gutter_max_author_length
25198                    .map(|max_author_length| {
25199                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
25200                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
25201
25202                        /// The number of characters to dedicate to gaps and margins.
25203                        const SPACING_WIDTH: usize = 4;
25204
25205                        let max_char_count = max_author_length.min(renderer.max_author_length())
25206                            + ::git::SHORT_SHA_LENGTH
25207                            + MAX_RELATIVE_TIMESTAMP.len()
25208                            + SPACING_WIDTH;
25209
25210                        ch_advance * max_char_count
25211                    });
25212
25213            let is_singleton = self.buffer_snapshot().is_singleton();
25214
25215            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
25216            left_padding += if !is_singleton {
25217                ch_width * 4.0
25218            } else if show_runnables || show_breakpoints {
25219                ch_width * 3.0
25220            } else if show_git_gutter && show_line_numbers {
25221                ch_width * 2.0
25222            } else if show_git_gutter || show_line_numbers {
25223                ch_width
25224            } else {
25225                px(0.)
25226            };
25227
25228            let shows_folds = is_singleton && gutter_settings.folds;
25229
25230            let right_padding = if shows_folds && show_line_numbers {
25231                ch_width * 4.0
25232            } else if shows_folds || (!is_singleton && show_line_numbers) {
25233                ch_width * 3.0
25234            } else if show_line_numbers {
25235                ch_width
25236            } else {
25237                px(0.)
25238            };
25239
25240            GutterDimensions {
25241                left_padding,
25242                right_padding,
25243                width: line_gutter_width + left_padding + right_padding,
25244                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
25245                git_blame_entries_width,
25246            }
25247        } else if self.offset_content {
25248            GutterDimensions::default_with_margin(font_id, font_size, cx)
25249        } else {
25250            GutterDimensions::default()
25251        }
25252    }
25253
25254    pub fn render_crease_toggle(
25255        &self,
25256        buffer_row: MultiBufferRow,
25257        row_contains_cursor: bool,
25258        editor: Entity<Editor>,
25259        window: &mut Window,
25260        cx: &mut App,
25261    ) -> Option<AnyElement> {
25262        let folded = self.is_line_folded(buffer_row);
25263        let mut is_foldable = false;
25264
25265        if let Some(crease) = self
25266            .crease_snapshot
25267            .query_row(buffer_row, self.buffer_snapshot())
25268        {
25269            is_foldable = true;
25270            match crease {
25271                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
25272                    if let Some(render_toggle) = render_toggle {
25273                        let toggle_callback =
25274                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
25275                                if folded {
25276                                    editor.update(cx, |editor, cx| {
25277                                        editor.fold_at(buffer_row, window, cx)
25278                                    });
25279                                } else {
25280                                    editor.update(cx, |editor, cx| {
25281                                        editor.unfold_at(buffer_row, window, cx)
25282                                    });
25283                                }
25284                            });
25285                        return Some((render_toggle)(
25286                            buffer_row,
25287                            folded,
25288                            toggle_callback,
25289                            window,
25290                            cx,
25291                        ));
25292                    }
25293                }
25294            }
25295        }
25296
25297        is_foldable |= self.starts_indent(buffer_row);
25298
25299        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
25300            Some(
25301                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
25302                    .toggle_state(folded)
25303                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
25304                        if folded {
25305                            this.unfold_at(buffer_row, window, cx);
25306                        } else {
25307                            this.fold_at(buffer_row, window, cx);
25308                        }
25309                    }))
25310                    .into_any_element(),
25311            )
25312        } else {
25313            None
25314        }
25315    }
25316
25317    pub fn render_crease_trailer(
25318        &self,
25319        buffer_row: MultiBufferRow,
25320        window: &mut Window,
25321        cx: &mut App,
25322    ) -> Option<AnyElement> {
25323        let folded = self.is_line_folded(buffer_row);
25324        if let Crease::Inline { render_trailer, .. } = self
25325            .crease_snapshot
25326            .query_row(buffer_row, self.buffer_snapshot())?
25327        {
25328            let render_trailer = render_trailer.as_ref()?;
25329            Some(render_trailer(buffer_row, folded, window, cx))
25330        } else {
25331            None
25332        }
25333    }
25334
25335    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
25336        let digit_count = self.widest_line_number().ilog10() + 1;
25337        column_pixels(style, digit_count as usize, window)
25338    }
25339
25340    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
25341    ///
25342    /// This is positive if `base` is before `line`.
25343    fn relative_line_delta(&self, base: DisplayRow, line: DisplayRow) -> i64 {
25344        let point = DisplayPoint::new(line, 0).to_point(self);
25345        self.relative_line_delta_to_point(base, point)
25346    }
25347
25348    /// Returns the line delta from `base` to `point` in the multibuffer, ignoring wrapped lines.
25349    ///
25350    /// This is positive if `base` is before `point`.
25351    pub fn relative_line_delta_to_point(&self, base: DisplayRow, point: Point) -> i64 {
25352        let base_point = DisplayPoint::new(base, 0).to_point(self);
25353        point.row as i64 - base_point.row as i64
25354    }
25355
25356    /// Returns the line delta from `base` to `line` in the multibuffer, counting wrapped lines.
25357    ///
25358    /// This is positive if `base` is before `line`.
25359    fn relative_wrapped_line_delta(&self, base: DisplayRow, line: DisplayRow) -> i64 {
25360        let point = DisplayPoint::new(line, 0).to_point(self);
25361        self.relative_wrapped_line_delta_to_point(base, point)
25362    }
25363
25364    /// Returns the line delta from `base` to `point` in the multibuffer, counting wrapped lines.
25365    ///
25366    /// This is positive if `base` is before `point`.
25367    pub fn relative_wrapped_line_delta_to_point(&self, base: DisplayRow, point: Point) -> i64 {
25368        let base_point = DisplayPoint::new(base, 0).to_point(self);
25369        let wrap_snapshot = self.wrap_snapshot();
25370        let base_wrap_row = wrap_snapshot.make_wrap_point(base_point, Bias::Left).row();
25371        let wrap_row = wrap_snapshot.make_wrap_point(point, Bias::Left).row();
25372        wrap_row.0 as i64 - base_wrap_row.0 as i64
25373    }
25374
25375    /// Returns the unsigned relative line number to display for each row in `rows`.
25376    ///
25377    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
25378    pub fn calculate_relative_line_numbers(
25379        &self,
25380        rows: &Range<DisplayRow>,
25381        relative_to: DisplayRow,
25382        count_wrapped_lines: bool,
25383    ) -> HashMap<DisplayRow, u32> {
25384        let initial_offset = if count_wrapped_lines {
25385            self.relative_wrapped_line_delta(relative_to, rows.start)
25386        } else {
25387            self.relative_line_delta(relative_to, rows.start)
25388        };
25389        let display_row_infos = self
25390            .row_infos(rows.start)
25391            .take(rows.len())
25392            .enumerate()
25393            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info));
25394        display_row_infos
25395            .filter(|(_row, row_info)| {
25396                row_info.buffer_row.is_some()
25397                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
25398            })
25399            .enumerate()
25400            .map(|(i, (row, _row_info))| (row, (initial_offset + i as i64).unsigned_abs() as u32))
25401            .collect()
25402    }
25403}
25404
25405pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
25406    let font_size = style.text.font_size.to_pixels(window.rem_size());
25407    let layout = window.text_system().shape_line(
25408        SharedString::from(" ".repeat(column)),
25409        font_size,
25410        &[TextRun {
25411            len: column,
25412            font: style.text.font(),
25413            color: Hsla::default(),
25414            ..Default::default()
25415        }],
25416        None,
25417    );
25418
25419    layout.width
25420}
25421
25422impl Deref for EditorSnapshot {
25423    type Target = DisplaySnapshot;
25424
25425    fn deref(&self) -> &Self::Target {
25426        &self.display_snapshot
25427    }
25428}
25429
25430#[derive(Clone, Debug, PartialEq, Eq)]
25431pub enum EditorEvent {
25432    InputIgnored {
25433        text: Arc<str>,
25434    },
25435    InputHandled {
25436        utf16_range_to_replace: Option<Range<isize>>,
25437        text: Arc<str>,
25438    },
25439    ExcerptsAdded {
25440        buffer: Entity<Buffer>,
25441        predecessor: ExcerptId,
25442        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
25443    },
25444    ExcerptsRemoved {
25445        ids: Vec<ExcerptId>,
25446        removed_buffer_ids: Vec<BufferId>,
25447    },
25448    BufferFoldToggled {
25449        ids: Vec<ExcerptId>,
25450        folded: bool,
25451    },
25452    ExcerptsEdited {
25453        ids: Vec<ExcerptId>,
25454    },
25455    ExcerptsExpanded {
25456        ids: Vec<ExcerptId>,
25457    },
25458    BufferEdited,
25459    Edited {
25460        transaction_id: clock::Lamport,
25461    },
25462    Reparsed(BufferId),
25463    Focused,
25464    FocusedIn,
25465    Blurred,
25466    DirtyChanged,
25467    Saved,
25468    TitleChanged,
25469    SelectionsChanged {
25470        local: bool,
25471    },
25472    ScrollPositionChanged {
25473        local: bool,
25474        autoscroll: bool,
25475    },
25476    TransactionUndone {
25477        transaction_id: clock::Lamport,
25478    },
25479    TransactionBegun {
25480        transaction_id: clock::Lamport,
25481    },
25482    CursorShapeChanged,
25483    BreadcrumbsChanged,
25484    PushedToNavHistory {
25485        anchor: Anchor,
25486        is_deactivate: bool,
25487    },
25488}
25489
25490impl EventEmitter<EditorEvent> for Editor {}
25491
25492impl Focusable for Editor {
25493    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25494        self.focus_handle.clone()
25495    }
25496}
25497
25498impl Render for Editor {
25499    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25500        EditorElement::new(&cx.entity(), self.create_style(cx))
25501    }
25502}
25503
25504impl EntityInputHandler for Editor {
25505    fn text_for_range(
25506        &mut self,
25507        range_utf16: Range<usize>,
25508        adjusted_range: &mut Option<Range<usize>>,
25509        _: &mut Window,
25510        cx: &mut Context<Self>,
25511    ) -> Option<String> {
25512        let snapshot = self.buffer.read(cx).read(cx);
25513        let start = snapshot.clip_offset_utf16(
25514            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25515            Bias::Left,
25516        );
25517        let end = snapshot.clip_offset_utf16(
25518            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25519            Bias::Right,
25520        );
25521        if (start.0.0..end.0.0) != range_utf16 {
25522            adjusted_range.replace(start.0.0..end.0.0);
25523        }
25524        Some(snapshot.text_for_range(start..end).collect())
25525    }
25526
25527    fn selected_text_range(
25528        &mut self,
25529        ignore_disabled_input: bool,
25530        _: &mut Window,
25531        cx: &mut Context<Self>,
25532    ) -> Option<UTF16Selection> {
25533        // Prevent the IME menu from appearing when holding down an alphabetic key
25534        // while input is disabled.
25535        if !ignore_disabled_input && !self.input_enabled {
25536            return None;
25537        }
25538
25539        let selection = self
25540            .selections
25541            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25542        let range = selection.range();
25543
25544        Some(UTF16Selection {
25545            range: range.start.0.0..range.end.0.0,
25546            reversed: selection.reversed,
25547        })
25548    }
25549
25550    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25551        let snapshot = self.buffer.read(cx).read(cx);
25552        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25553        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25554    }
25555
25556    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25557        self.clear_highlights::<InputComposition>(cx);
25558        self.ime_transaction.take();
25559    }
25560
25561    fn replace_text_in_range(
25562        &mut self,
25563        range_utf16: Option<Range<usize>>,
25564        text: &str,
25565        window: &mut Window,
25566        cx: &mut Context<Self>,
25567    ) {
25568        if !self.input_enabled {
25569            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25570            return;
25571        }
25572
25573        self.transact(window, cx, |this, window, cx| {
25574            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25575                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25576                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25577                Some(this.selection_replacement_ranges(range_utf16, cx))
25578            } else {
25579                this.marked_text_ranges(cx)
25580            };
25581
25582            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25583                let newest_selection_id = this.selections.newest_anchor().id;
25584                this.selections
25585                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25586                    .iter()
25587                    .zip(ranges_to_replace.iter())
25588                    .find_map(|(selection, range)| {
25589                        if selection.id == newest_selection_id {
25590                            Some(
25591                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25592                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25593                            )
25594                        } else {
25595                            None
25596                        }
25597                    })
25598            });
25599
25600            cx.emit(EditorEvent::InputHandled {
25601                utf16_range_to_replace: range_to_replace,
25602                text: text.into(),
25603            });
25604
25605            if let Some(new_selected_ranges) = new_selected_ranges {
25606                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25607                    selections.select_ranges(new_selected_ranges)
25608                });
25609                this.backspace(&Default::default(), window, cx);
25610            }
25611
25612            this.handle_input(text, window, cx);
25613        });
25614
25615        if let Some(transaction) = self.ime_transaction {
25616            self.buffer.update(cx, |buffer, cx| {
25617                buffer.group_until_transaction(transaction, cx);
25618            });
25619        }
25620
25621        self.unmark_text(window, cx);
25622    }
25623
25624    fn replace_and_mark_text_in_range(
25625        &mut self,
25626        range_utf16: Option<Range<usize>>,
25627        text: &str,
25628        new_selected_range_utf16: Option<Range<usize>>,
25629        window: &mut Window,
25630        cx: &mut Context<Self>,
25631    ) {
25632        if !self.input_enabled {
25633            return;
25634        }
25635
25636        let transaction = self.transact(window, cx, |this, window, cx| {
25637            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25638                let snapshot = this.buffer.read(cx).read(cx);
25639                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25640                    for marked_range in &mut marked_ranges {
25641                        marked_range.end = marked_range.start + relative_range_utf16.end;
25642                        marked_range.start += relative_range_utf16.start;
25643                        marked_range.start =
25644                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25645                        marked_range.end =
25646                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25647                    }
25648                }
25649                Some(marked_ranges)
25650            } else if let Some(range_utf16) = range_utf16 {
25651                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25652                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25653                Some(this.selection_replacement_ranges(range_utf16, cx))
25654            } else {
25655                None
25656            };
25657
25658            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25659                let newest_selection_id = this.selections.newest_anchor().id;
25660                this.selections
25661                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25662                    .iter()
25663                    .zip(ranges_to_replace.iter())
25664                    .find_map(|(selection, range)| {
25665                        if selection.id == newest_selection_id {
25666                            Some(
25667                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25668                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25669                            )
25670                        } else {
25671                            None
25672                        }
25673                    })
25674            });
25675
25676            cx.emit(EditorEvent::InputHandled {
25677                utf16_range_to_replace: range_to_replace,
25678                text: text.into(),
25679            });
25680
25681            if let Some(ranges) = ranges_to_replace {
25682                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25683                    s.select_ranges(ranges)
25684                });
25685            }
25686
25687            let marked_ranges = {
25688                let snapshot = this.buffer.read(cx).read(cx);
25689                this.selections
25690                    .disjoint_anchors_arc()
25691                    .iter()
25692                    .map(|selection| {
25693                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25694                    })
25695                    .collect::<Vec<_>>()
25696            };
25697
25698            if text.is_empty() {
25699                this.unmark_text(window, cx);
25700            } else {
25701                this.highlight_text::<InputComposition>(
25702                    marked_ranges.clone(),
25703                    HighlightStyle {
25704                        underline: Some(UnderlineStyle {
25705                            thickness: px(1.),
25706                            color: None,
25707                            wavy: false,
25708                        }),
25709                        ..Default::default()
25710                    },
25711                    cx,
25712                );
25713            }
25714
25715            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25716            let use_autoclose = this.use_autoclose;
25717            let use_auto_surround = this.use_auto_surround;
25718            this.set_use_autoclose(false);
25719            this.set_use_auto_surround(false);
25720            this.handle_input(text, window, cx);
25721            this.set_use_autoclose(use_autoclose);
25722            this.set_use_auto_surround(use_auto_surround);
25723
25724            if let Some(new_selected_range) = new_selected_range_utf16 {
25725                let snapshot = this.buffer.read(cx).read(cx);
25726                let new_selected_ranges = marked_ranges
25727                    .into_iter()
25728                    .map(|marked_range| {
25729                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25730                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25731                            insertion_start.0 + new_selected_range.start,
25732                        ));
25733                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25734                            insertion_start.0 + new_selected_range.end,
25735                        ));
25736                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25737                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25738                    })
25739                    .collect::<Vec<_>>();
25740
25741                drop(snapshot);
25742                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25743                    selections.select_ranges(new_selected_ranges)
25744                });
25745            }
25746        });
25747
25748        self.ime_transaction = self.ime_transaction.or(transaction);
25749        if let Some(transaction) = self.ime_transaction {
25750            self.buffer.update(cx, |buffer, cx| {
25751                buffer.group_until_transaction(transaction, cx);
25752            });
25753        }
25754
25755        if self.text_highlights::<InputComposition>(cx).is_none() {
25756            self.ime_transaction.take();
25757        }
25758    }
25759
25760    fn bounds_for_range(
25761        &mut self,
25762        range_utf16: Range<usize>,
25763        element_bounds: gpui::Bounds<Pixels>,
25764        window: &mut Window,
25765        cx: &mut Context<Self>,
25766    ) -> Option<gpui::Bounds<Pixels>> {
25767        let text_layout_details = self.text_layout_details(window);
25768        let CharacterDimensions {
25769            em_width,
25770            em_advance,
25771            line_height,
25772        } = self.character_dimensions(window);
25773
25774        let snapshot = self.snapshot(window, cx);
25775        let scroll_position = snapshot.scroll_position();
25776        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25777
25778        let start =
25779            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25780        let x = Pixels::from(
25781            ScrollOffset::from(
25782                snapshot.x_for_display_point(start, &text_layout_details)
25783                    + self.gutter_dimensions.full_width(),
25784            ) - scroll_left,
25785        );
25786        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25787
25788        Some(Bounds {
25789            origin: element_bounds.origin + point(x, y),
25790            size: size(em_width, line_height),
25791        })
25792    }
25793
25794    fn character_index_for_point(
25795        &mut self,
25796        point: gpui::Point<Pixels>,
25797        _window: &mut Window,
25798        _cx: &mut Context<Self>,
25799    ) -> Option<usize> {
25800        let position_map = self.last_position_map.as_ref()?;
25801        if !position_map.text_hitbox.contains(&point) {
25802            return None;
25803        }
25804        let display_point = position_map.point_for_position(point).previous_valid;
25805        let anchor = position_map
25806            .snapshot
25807            .display_point_to_anchor(display_point, Bias::Left);
25808        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25809        Some(utf16_offset.0.0)
25810    }
25811
25812    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25813        self.input_enabled
25814    }
25815}
25816
25817trait SelectionExt {
25818    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25819    fn spanned_rows(
25820        &self,
25821        include_end_if_at_line_start: bool,
25822        map: &DisplaySnapshot,
25823    ) -> Range<MultiBufferRow>;
25824}
25825
25826impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25827    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25828        let start = self
25829            .start
25830            .to_point(map.buffer_snapshot())
25831            .to_display_point(map);
25832        let end = self
25833            .end
25834            .to_point(map.buffer_snapshot())
25835            .to_display_point(map);
25836        if self.reversed {
25837            end..start
25838        } else {
25839            start..end
25840        }
25841    }
25842
25843    fn spanned_rows(
25844        &self,
25845        include_end_if_at_line_start: bool,
25846        map: &DisplaySnapshot,
25847    ) -> Range<MultiBufferRow> {
25848        let start = self.start.to_point(map.buffer_snapshot());
25849        let mut end = self.end.to_point(map.buffer_snapshot());
25850        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25851            end.row -= 1;
25852        }
25853
25854        let buffer_start = map.prev_line_boundary(start).0;
25855        let buffer_end = map.next_line_boundary(end).0;
25856        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25857    }
25858}
25859
25860impl<T: InvalidationRegion> InvalidationStack<T> {
25861    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25862    where
25863        S: Clone + ToOffset,
25864    {
25865        while let Some(region) = self.last() {
25866            let all_selections_inside_invalidation_ranges =
25867                if selections.len() == region.ranges().len() {
25868                    selections
25869                        .iter()
25870                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25871                        .all(|(selection, invalidation_range)| {
25872                            let head = selection.head().to_offset(buffer);
25873                            invalidation_range.start <= head && invalidation_range.end >= head
25874                        })
25875                } else {
25876                    false
25877                };
25878
25879            if all_selections_inside_invalidation_ranges {
25880                break;
25881            } else {
25882                self.pop();
25883            }
25884        }
25885    }
25886}
25887
25888impl<T> Default for InvalidationStack<T> {
25889    fn default() -> Self {
25890        Self(Default::default())
25891    }
25892}
25893
25894impl<T> Deref for InvalidationStack<T> {
25895    type Target = Vec<T>;
25896
25897    fn deref(&self) -> &Self::Target {
25898        &self.0
25899    }
25900}
25901
25902impl<T> DerefMut for InvalidationStack<T> {
25903    fn deref_mut(&mut self) -> &mut Self::Target {
25904        &mut self.0
25905    }
25906}
25907
25908impl InvalidationRegion for SnippetState {
25909    fn ranges(&self) -> &[Range<Anchor>] {
25910        &self.ranges[self.active_index]
25911    }
25912}
25913
25914fn edit_prediction_edit_text(
25915    current_snapshot: &BufferSnapshot,
25916    edits: &[(Range<Anchor>, impl AsRef<str>)],
25917    edit_preview: &EditPreview,
25918    include_deletions: bool,
25919    cx: &App,
25920) -> HighlightedText {
25921    let edits = edits
25922        .iter()
25923        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25924        .collect::<Vec<_>>();
25925
25926    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25927}
25928
25929fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25930    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25931    // Just show the raw edit text with basic styling
25932    let mut text = String::new();
25933    let mut highlights = Vec::new();
25934
25935    let insertion_highlight_style = HighlightStyle {
25936        color: Some(cx.theme().colors().text),
25937        ..Default::default()
25938    };
25939
25940    for (_, edit_text) in edits {
25941        let start_offset = text.len();
25942        text.push_str(edit_text);
25943        let end_offset = text.len();
25944
25945        if start_offset < end_offset {
25946            highlights.push((start_offset..end_offset, insertion_highlight_style));
25947        }
25948    }
25949
25950    HighlightedText {
25951        text: text.into(),
25952        highlights,
25953    }
25954}
25955
25956pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25957    match severity {
25958        lsp::DiagnosticSeverity::ERROR => colors.error,
25959        lsp::DiagnosticSeverity::WARNING => colors.warning,
25960        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25961        lsp::DiagnosticSeverity::HINT => colors.info,
25962        _ => colors.ignored,
25963    }
25964}
25965
25966pub fn styled_runs_for_code_label<'a>(
25967    label: &'a CodeLabel,
25968    syntax_theme: &'a theme::SyntaxTheme,
25969    local_player: &'a theme::PlayerColor,
25970) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25971    let fade_out = HighlightStyle {
25972        fade_out: Some(0.35),
25973        ..Default::default()
25974    };
25975
25976    let mut prev_end = label.filter_range.end;
25977    label
25978        .runs
25979        .iter()
25980        .enumerate()
25981        .flat_map(move |(ix, (range, highlight_id))| {
25982            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25983                HighlightStyle {
25984                    color: Some(local_player.cursor),
25985                    ..Default::default()
25986                }
25987            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25988                HighlightStyle {
25989                    background_color: Some(local_player.selection),
25990                    ..Default::default()
25991                }
25992            } else if let Some(style) = highlight_id.style(syntax_theme) {
25993                style
25994            } else {
25995                return Default::default();
25996            };
25997            let muted_style = style.highlight(fade_out);
25998
25999            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
26000            if range.start >= label.filter_range.end {
26001                if range.start > prev_end {
26002                    runs.push((prev_end..range.start, fade_out));
26003                }
26004                runs.push((range.clone(), muted_style));
26005            } else if range.end <= label.filter_range.end {
26006                runs.push((range.clone(), style));
26007            } else {
26008                runs.push((range.start..label.filter_range.end, style));
26009                runs.push((label.filter_range.end..range.end, muted_style));
26010            }
26011            prev_end = cmp::max(prev_end, range.end);
26012
26013            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
26014                runs.push((prev_end..label.text.len(), fade_out));
26015            }
26016
26017            runs
26018        })
26019}
26020
26021pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
26022    let mut prev_index = 0;
26023    let mut prev_codepoint: Option<char> = None;
26024    text.char_indices()
26025        .chain([(text.len(), '\0')])
26026        .filter_map(move |(index, codepoint)| {
26027            let prev_codepoint = prev_codepoint.replace(codepoint)?;
26028            let is_boundary = index == text.len()
26029                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
26030                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
26031            if is_boundary {
26032                let chunk = &text[prev_index..index];
26033                prev_index = index;
26034                Some(chunk)
26035            } else {
26036                None
26037            }
26038        })
26039}
26040
26041/// Given a string of text immediately before the cursor, iterates over possible
26042/// strings a snippet could match to. More precisely: returns an iterator over
26043/// suffixes of `text` created by splitting at word boundaries (before & after
26044/// every non-word character).
26045///
26046/// Shorter suffixes are returned first.
26047pub(crate) fn snippet_candidate_suffixes(
26048    text: &str,
26049    is_word_char: impl Fn(char) -> bool,
26050) -> impl std::iter::Iterator<Item = &str> {
26051    let mut prev_index = text.len();
26052    let mut prev_codepoint = None;
26053    text.char_indices()
26054        .rev()
26055        .chain([(0, '\0')])
26056        .filter_map(move |(index, codepoint)| {
26057            let prev_index = std::mem::replace(&mut prev_index, index);
26058            let prev_codepoint = prev_codepoint.replace(codepoint)?;
26059            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
26060                None
26061            } else {
26062                let chunk = &text[prev_index..]; // go to end of string
26063                Some(chunk)
26064            }
26065        })
26066}
26067
26068pub trait RangeToAnchorExt: Sized {
26069    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
26070
26071    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
26072        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
26073        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
26074    }
26075}
26076
26077impl<T: ToOffset> RangeToAnchorExt for Range<T> {
26078    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
26079        let start_offset = self.start.to_offset(snapshot);
26080        let end_offset = self.end.to_offset(snapshot);
26081        if start_offset == end_offset {
26082            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
26083        } else {
26084            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
26085        }
26086    }
26087}
26088
26089pub trait RowExt {
26090    fn as_f64(&self) -> f64;
26091
26092    fn next_row(&self) -> Self;
26093
26094    fn previous_row(&self) -> Self;
26095
26096    fn minus(&self, other: Self) -> u32;
26097}
26098
26099impl RowExt for DisplayRow {
26100    fn as_f64(&self) -> f64 {
26101        self.0 as _
26102    }
26103
26104    fn next_row(&self) -> Self {
26105        Self(self.0 + 1)
26106    }
26107
26108    fn previous_row(&self) -> Self {
26109        Self(self.0.saturating_sub(1))
26110    }
26111
26112    fn minus(&self, other: Self) -> u32 {
26113        self.0 - other.0
26114    }
26115}
26116
26117impl RowExt for MultiBufferRow {
26118    fn as_f64(&self) -> f64 {
26119        self.0 as _
26120    }
26121
26122    fn next_row(&self) -> Self {
26123        Self(self.0 + 1)
26124    }
26125
26126    fn previous_row(&self) -> Self {
26127        Self(self.0.saturating_sub(1))
26128    }
26129
26130    fn minus(&self, other: Self) -> u32 {
26131        self.0 - other.0
26132    }
26133}
26134
26135trait RowRangeExt {
26136    type Row;
26137
26138    fn len(&self) -> usize;
26139
26140    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
26141}
26142
26143impl RowRangeExt for Range<MultiBufferRow> {
26144    type Row = MultiBufferRow;
26145
26146    fn len(&self) -> usize {
26147        (self.end.0 - self.start.0) as usize
26148    }
26149
26150    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
26151        (self.start.0..self.end.0).map(MultiBufferRow)
26152    }
26153}
26154
26155impl RowRangeExt for Range<DisplayRow> {
26156    type Row = DisplayRow;
26157
26158    fn len(&self) -> usize {
26159        (self.end.0 - self.start.0) as usize
26160    }
26161
26162    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
26163        (self.start.0..self.end.0).map(DisplayRow)
26164    }
26165}
26166
26167/// If select range has more than one line, we
26168/// just point the cursor to range.start.
26169fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
26170    if range.start.row == range.end.row {
26171        range
26172    } else {
26173        range.start..range.start
26174    }
26175}
26176pub struct KillRing(ClipboardItem);
26177impl Global for KillRing {}
26178
26179const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
26180
26181enum BreakpointPromptEditAction {
26182    Log,
26183    Condition,
26184    HitCondition,
26185}
26186
26187struct BreakpointPromptEditor {
26188    pub(crate) prompt: Entity<Editor>,
26189    editor: WeakEntity<Editor>,
26190    breakpoint_anchor: Anchor,
26191    breakpoint: Breakpoint,
26192    edit_action: BreakpointPromptEditAction,
26193    block_ids: HashSet<CustomBlockId>,
26194    editor_margins: Arc<Mutex<EditorMargins>>,
26195    _subscriptions: Vec<Subscription>,
26196}
26197
26198impl BreakpointPromptEditor {
26199    const MAX_LINES: u8 = 4;
26200
26201    fn new(
26202        editor: WeakEntity<Editor>,
26203        breakpoint_anchor: Anchor,
26204        breakpoint: Breakpoint,
26205        edit_action: BreakpointPromptEditAction,
26206        window: &mut Window,
26207        cx: &mut Context<Self>,
26208    ) -> Self {
26209        let base_text = match edit_action {
26210            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
26211            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
26212            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
26213        }
26214        .map(|msg| msg.to_string())
26215        .unwrap_or_default();
26216
26217        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
26218        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
26219
26220        let prompt = cx.new(|cx| {
26221            let mut prompt = Editor::new(
26222                EditorMode::AutoHeight {
26223                    min_lines: 1,
26224                    max_lines: Some(Self::MAX_LINES as usize),
26225                },
26226                buffer,
26227                None,
26228                window,
26229                cx,
26230            );
26231            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
26232            prompt.set_show_cursor_when_unfocused(false, cx);
26233            prompt.set_placeholder_text(
26234                match edit_action {
26235                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
26236                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
26237                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
26238                },
26239                window,
26240                cx,
26241            );
26242
26243            prompt
26244        });
26245
26246        Self {
26247            prompt,
26248            editor,
26249            breakpoint_anchor,
26250            breakpoint,
26251            edit_action,
26252            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
26253            block_ids: Default::default(),
26254            _subscriptions: vec![],
26255        }
26256    }
26257
26258    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
26259        self.block_ids.extend(block_ids)
26260    }
26261
26262    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
26263        if let Some(editor) = self.editor.upgrade() {
26264            let message = self
26265                .prompt
26266                .read(cx)
26267                .buffer
26268                .read(cx)
26269                .as_singleton()
26270                .expect("A multi buffer in breakpoint prompt isn't possible")
26271                .read(cx)
26272                .as_rope()
26273                .to_string();
26274
26275            editor.update(cx, |editor, cx| {
26276                editor.edit_breakpoint_at_anchor(
26277                    self.breakpoint_anchor,
26278                    self.breakpoint.clone(),
26279                    match self.edit_action {
26280                        BreakpointPromptEditAction::Log => {
26281                            BreakpointEditAction::EditLogMessage(message.into())
26282                        }
26283                        BreakpointPromptEditAction::Condition => {
26284                            BreakpointEditAction::EditCondition(message.into())
26285                        }
26286                        BreakpointPromptEditAction::HitCondition => {
26287                            BreakpointEditAction::EditHitCondition(message.into())
26288                        }
26289                    },
26290                    cx,
26291                );
26292
26293                editor.remove_blocks(self.block_ids.clone(), None, cx);
26294                cx.focus_self(window);
26295            });
26296        }
26297    }
26298
26299    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
26300        self.editor
26301            .update(cx, |editor, cx| {
26302                editor.remove_blocks(self.block_ids.clone(), None, cx);
26303                window.focus(&editor.focus_handle, cx);
26304            })
26305            .log_err();
26306    }
26307
26308    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
26309        let settings = ThemeSettings::get_global(cx);
26310        let text_style = TextStyle {
26311            color: if self.prompt.read(cx).read_only(cx) {
26312                cx.theme().colors().text_disabled
26313            } else {
26314                cx.theme().colors().text
26315            },
26316            font_family: settings.buffer_font.family.clone(),
26317            font_fallbacks: settings.buffer_font.fallbacks.clone(),
26318            font_size: settings.buffer_font_size(cx).into(),
26319            font_weight: settings.buffer_font.weight,
26320            line_height: relative(settings.buffer_line_height.value()),
26321            ..Default::default()
26322        };
26323        EditorElement::new(
26324            &self.prompt,
26325            EditorStyle {
26326                background: cx.theme().colors().editor_background,
26327                local_player: cx.theme().players().local(),
26328                text: text_style,
26329                ..Default::default()
26330            },
26331        )
26332    }
26333}
26334
26335impl Render for BreakpointPromptEditor {
26336    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26337        let editor_margins = *self.editor_margins.lock();
26338        let gutter_dimensions = editor_margins.gutter;
26339        h_flex()
26340            .key_context("Editor")
26341            .bg(cx.theme().colors().editor_background)
26342            .border_y_1()
26343            .border_color(cx.theme().status().info_border)
26344            .size_full()
26345            .py(window.line_height() / 2.5)
26346            .on_action(cx.listener(Self::confirm))
26347            .on_action(cx.listener(Self::cancel))
26348            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
26349            .child(div().flex_1().child(self.render_prompt_editor(cx)))
26350    }
26351}
26352
26353impl Focusable for BreakpointPromptEditor {
26354    fn focus_handle(&self, cx: &App) -> FocusHandle {
26355        self.prompt.focus_handle(cx)
26356    }
26357}
26358
26359fn all_edits_insertions_or_deletions(
26360    edits: &Vec<(Range<Anchor>, Arc<str>)>,
26361    snapshot: &MultiBufferSnapshot,
26362) -> bool {
26363    let mut all_insertions = true;
26364    let mut all_deletions = true;
26365
26366    for (range, new_text) in edits.iter() {
26367        let range_is_empty = range.to_offset(snapshot).is_empty();
26368        let text_is_empty = new_text.is_empty();
26369
26370        if range_is_empty != text_is_empty {
26371            if range_is_empty {
26372                all_deletions = false;
26373            } else {
26374                all_insertions = false;
26375            }
26376        } else {
26377            return false;
26378        }
26379
26380        if !all_insertions && !all_deletions {
26381            return false;
26382        }
26383    }
26384    all_insertions || all_deletions
26385}
26386
26387struct MissingEditPredictionKeybindingTooltip;
26388
26389impl Render for MissingEditPredictionKeybindingTooltip {
26390    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26391        ui::tooltip_container(cx, |container, cx| {
26392            container
26393                .flex_shrink_0()
26394                .max_w_80()
26395                .min_h(rems_from_px(124.))
26396                .justify_between()
26397                .child(
26398                    v_flex()
26399                        .flex_1()
26400                        .text_ui_sm(cx)
26401                        .child(Label::new("Conflict with Accept Keybinding"))
26402                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
26403                )
26404                .child(
26405                    h_flex()
26406                        .pb_1()
26407                        .gap_1()
26408                        .items_end()
26409                        .w_full()
26410                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
26411                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
26412                        }))
26413                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
26414                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
26415                        })),
26416                )
26417        })
26418    }
26419}
26420
26421#[derive(Debug, Clone, Copy, PartialEq)]
26422pub struct LineHighlight {
26423    pub background: Background,
26424    pub border: Option<gpui::Hsla>,
26425    pub include_gutter: bool,
26426    pub type_id: Option<TypeId>,
26427}
26428
26429struct LineManipulationResult {
26430    pub new_text: String,
26431    pub line_count_before: usize,
26432    pub line_count_after: usize,
26433}
26434
26435fn render_diff_hunk_controls(
26436    row: u32,
26437    status: &DiffHunkStatus,
26438    hunk_range: Range<Anchor>,
26439    is_created_file: bool,
26440    line_height: Pixels,
26441    editor: &Entity<Editor>,
26442    _window: &mut Window,
26443    cx: &mut App,
26444) -> AnyElement {
26445    h_flex()
26446        .h(line_height)
26447        .mr_1()
26448        .gap_1()
26449        .px_0p5()
26450        .pb_1()
26451        .border_x_1()
26452        .border_b_1()
26453        .border_color(cx.theme().colors().border_variant)
26454        .rounded_b_lg()
26455        .bg(cx.theme().colors().editor_background)
26456        .gap_1()
26457        .block_mouse_except_scroll()
26458        .shadow_md()
26459        .child(if status.has_secondary_hunk() {
26460            Button::new(("stage", row as u64), "Stage")
26461                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26462                .tooltip({
26463                    let focus_handle = editor.focus_handle(cx);
26464                    move |_window, cx| {
26465                        Tooltip::for_action_in(
26466                            "Stage Hunk",
26467                            &::git::ToggleStaged,
26468                            &focus_handle,
26469                            cx,
26470                        )
26471                    }
26472                })
26473                .on_click({
26474                    let editor = editor.clone();
26475                    move |_event, _window, cx| {
26476                        editor.update(cx, |editor, cx| {
26477                            editor.stage_or_unstage_diff_hunks(
26478                                true,
26479                                vec![hunk_range.start..hunk_range.start],
26480                                cx,
26481                            );
26482                        });
26483                    }
26484                })
26485        } else {
26486            Button::new(("unstage", row as u64), "Unstage")
26487                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26488                .tooltip({
26489                    let focus_handle = editor.focus_handle(cx);
26490                    move |_window, cx| {
26491                        Tooltip::for_action_in(
26492                            "Unstage Hunk",
26493                            &::git::ToggleStaged,
26494                            &focus_handle,
26495                            cx,
26496                        )
26497                    }
26498                })
26499                .on_click({
26500                    let editor = editor.clone();
26501                    move |_event, _window, cx| {
26502                        editor.update(cx, |editor, cx| {
26503                            editor.stage_or_unstage_diff_hunks(
26504                                false,
26505                                vec![hunk_range.start..hunk_range.start],
26506                                cx,
26507                            );
26508                        });
26509                    }
26510                })
26511        })
26512        .child(
26513            Button::new(("restore", row as u64), "Restore")
26514                .tooltip({
26515                    let focus_handle = editor.focus_handle(cx);
26516                    move |_window, cx| {
26517                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26518                    }
26519                })
26520                .on_click({
26521                    let editor = editor.clone();
26522                    move |_event, window, cx| {
26523                        editor.update(cx, |editor, cx| {
26524                            let snapshot = editor.snapshot(window, cx);
26525                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26526                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26527                        });
26528                    }
26529                })
26530                .disabled(is_created_file),
26531        )
26532        .when(
26533            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26534            |el| {
26535                el.child(
26536                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26537                        .shape(IconButtonShape::Square)
26538                        .icon_size(IconSize::Small)
26539                        // .disabled(!has_multiple_hunks)
26540                        .tooltip({
26541                            let focus_handle = editor.focus_handle(cx);
26542                            move |_window, cx| {
26543                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26544                            }
26545                        })
26546                        .on_click({
26547                            let editor = editor.clone();
26548                            move |_event, window, cx| {
26549                                editor.update(cx, |editor, cx| {
26550                                    let snapshot = editor.snapshot(window, cx);
26551                                    let position =
26552                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26553                                    editor.go_to_hunk_before_or_after_position(
26554                                        &snapshot,
26555                                        position,
26556                                        Direction::Next,
26557                                        window,
26558                                        cx,
26559                                    );
26560                                    editor.expand_selected_diff_hunks(cx);
26561                                });
26562                            }
26563                        }),
26564                )
26565                .child(
26566                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26567                        .shape(IconButtonShape::Square)
26568                        .icon_size(IconSize::Small)
26569                        // .disabled(!has_multiple_hunks)
26570                        .tooltip({
26571                            let focus_handle = editor.focus_handle(cx);
26572                            move |_window, cx| {
26573                                Tooltip::for_action_in(
26574                                    "Previous Hunk",
26575                                    &GoToPreviousHunk,
26576                                    &focus_handle,
26577                                    cx,
26578                                )
26579                            }
26580                        })
26581                        .on_click({
26582                            let editor = editor.clone();
26583                            move |_event, window, cx| {
26584                                editor.update(cx, |editor, cx| {
26585                                    let snapshot = editor.snapshot(window, cx);
26586                                    let point =
26587                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26588                                    editor.go_to_hunk_before_or_after_position(
26589                                        &snapshot,
26590                                        point,
26591                                        Direction::Prev,
26592                                        window,
26593                                        cx,
26594                                    );
26595                                    editor.expand_selected_diff_hunks(cx);
26596                                });
26597                            }
26598                        }),
26599                )
26600            },
26601        )
26602        .into_any_element()
26603}
26604
26605pub fn multibuffer_context_lines(cx: &App) -> u32 {
26606    EditorSettings::try_get(cx)
26607        .map(|settings| settings.excerpt_context_lines)
26608        .unwrap_or(2)
26609        .min(32)
26610}